Friday, 21 April 2017

Http.sys update

Things have changed a bit since I wrote about self hosted web applications in .net and http.sys 4 years ago, so I'll write a short update.

In the past your (Microsoft based) self-hosting options were based on HttpListener, that relies on the powerful http.sys kernel driver. As you can read here we have now 2 alternatives for Asp.Net core. If we still want to leverage http.sys we'll be using the WebListener embeddable server. This is the evolution (it started as a fork) of the HttpListener. Notice that WebListener has been created just to take advantage of http.sys (by means of the HTTP Server API), so it is only available for Windows, it will not be ported to Linux. If you want to run your application on both platforms you should use the other alternative, Kestrel. Time ago the the Mono folks implemented HttpListener for Linux, which made much sense at that time as there was not any other alternative component, but with the multiplatform Kestrel there's no need to port WebListener.

There's an important general difference between Unix and Windows regarding ports. In Unix you need to be root in order to listen on a port below 1024 (a privileged port), but this limitation does not exist in Windows. So when running kestrel on Linux you'll have to be careful to use a port above 1024 (unless you want to run kestrel as root, that is not a particularly good idea).

On the other side, if using WebListener you'll also be have to be careful about ports and permissions, though this is due to how the underlying http.sys works. This kernel driver is the one that listens for http connections, and your WebListener application has to register with it (hey, listen on this port and redirect anything with this url prefix to me) so that it redirects the incoming connections to your application. If you are running your application as admin you'll be able to register on any port, but if you are not admin things can get a bit more complicated. Registering your application with http.sys for ports under 1024 is protected, so for a non admin user to be allowed to do so you will first have to configure http.sys giving the user permissions on that port/url. It's what you do with the netsh http add urlacl command.

When using Kestrel on Windows there are situations where you still need to be aware of http.sys, particularly if you are trying to run Kestrel on port 80. On some occasions this port will be already taken by http.sys, so if kestrel tries to listen on that port you will get an error. Notice that Kestrel is totally unaware of http.sys, so it does not try to register with http.sys, it just directly tries to take the port. As far as I know http.sys is loaded into (kernel) memory by Windows at start up (as many other drivers), but it will not start to listen on any port until a process asks for it. This is how it looks on my home machine.

Http.sys is loaded into memory and it has a couple of kernel threads running (Process Explorer shows these under a fictitious "system" process. If you check the TCP/IP connections for that pseudo-process you'll see that the http port is not taken, so I have no problem to start another web server on that port.

However, on my office laptop I can see that port 80 is taken by the "system" pseudo-process (hence, it had to be http.sys who is taking it). So some process that I'm not aware of has asked http.sys to listen on that port. In a situation like this, if we need port 80 for another Web Server not relying on http.sys, the best we can do is to disable http.sys as explained here.

Don't be confused by the use of sc to unload it. Http.sys is not a "normal" service (notice that you will not see it displayed on services.msc), but one kind of drivers (like http.sys) can be installed and loaded/unloaded through the sc service interface. This in the end calls into the CreateService function in advapi32.dll, passing as parameter the SERVICE_KERNEL_DRIVER value. So in a sense we could consider these drivers as "Kernel services".

No comments:

Post a Comment