That was interesting. Makes me want to write a server that services all 3 ports at once. Also for those playing at home your OS may require that the application has root/administrator access to open ports below 1024.
See the commented out ‘echo’ etc lines in point 3 - you’ll see echo + daytime there implemented as ‘internal’ (along with some others - ‘chargen’ service anyone? https://tools.ietf.org/html/rfc864)
When sshd dies, you don’t want Larry the intern starting up a new one and harvesting passwords.
In the long, long ago when people used rlogin, connecting from a low port meant the connection was root sanctioned, and therefore not lying about their identity.
Reserving these ports for root is a mechanism which allows a program running as root to implement any policy you choose (for those ports), instead of baking a complicated ACL policy into the kernel. It does, however, bake the policy that any program can open ports over 1024 into the kernel, which may not have been a good idea; for example, if you can listen on port 5900, you can trick people into revealing their VNC passwords.
Historically, yes, there were a lot of cases where someone was running sendmail fingerd or whatever as root because that was convenient, and got exploited. But you can bind to the port as root and then setuid to nobody, and in fact inetd lets you specify that right in the config file. Or you can have a little setuid-root program to bind the port for you. Or you can accept connections as root and then pass them off to non-root handler processes with SCM_RIGHTS.
The implementation has a bug, and doesn’t account for end-of-file. The method call client.gets will return nil after EOF; the program should check for that. There is a pull request to fix that on GitHub.
This isn’t about the protocol, but you should know my code for this is really sloppy because it was my first time attempting to use vim and literally everything was hard.
Just before I read this, in a flash I thought Gopher. Then I realised Gopher is not really dead, but ok, it’s not exactly used that much either.
Links like these used to work, until browsers took out support: gopher://gopher.quux.org
You can still get some support via plugins like this.
Speaking of ancient inetd services, tedu started an interesting discussion a little ways back on openbsd-tech about chargen (port 19):
https://marc.info/?t=141995818700003
https://en.wikipedia.org/wiki/Character_Generator_Protocol
This is great. I love discovering odd (almost quirky) little RFC’s for things like this. Great post!
I’m a teapot
Thanks! But I’ve heard of that one. It’s probably my favorite.
That was interesting. Makes me want to write a server that services all 3 ports at once. Also for those playing at home your OS may require that the application has root/administrator access to open ports below 1024.
The classic “spawn a process per connection” inetd would implement these services itself, rather than handle them in sub-proceses:
http://www.tldp.org/LDP/solrhe/Securing-Optimizing-Linux-RH-Edition-v1.3/chap5sec36.html
See the commented out ‘echo’ etc lines in point 3 - you’ll see echo + daytime there implemented as ‘internal’ (along with some others - ‘chargen’ service anyone? https://tools.ietf.org/html/rfc864)
What was the historical reason for the “must be elevated for ports below 1024”?
Doesn’t that pretty much just guarantee that a buggy server implementation is more exploitable?
When sshd dies, you don’t want Larry the intern starting up a new one and harvesting passwords.
In the long, long ago when people used rlogin, connecting from a low port meant the connection was root sanctioned, and therefore not lying about their identity.
This makes a sound argument for, say, having a list of explicit port bindings and reservations, at system startup. ACLs for programs, effectively.
It seems like a kludge otherwise. :(
You have to admit, it was a simple solution for a simpler age and works for the majority of cases.
Reserving these ports for root is a mechanism which allows a program running as root to implement any policy you choose (for those ports), instead of baking a complicated ACL policy into the kernel. It does, however, bake the policy that any program can open ports over 1024 into the kernel, which may not have been a good idea; for example, if you can listen on port 5900, you can trick people into revealing their VNC passwords.
I think you’re looking at it in reverse. It guarantees that normal users don’t bind below 1024 and try to impersonate system services.
Historically, yes, there were a lot of cases where someone was running sendmail fingerd or whatever as root because that was convenient, and got exploited. But you can bind to the port as root and then setuid to nobody, and in fact inetd lets you specify that right in the config file. Or you can have a little setuid-root program to bind the port for you. Or you can accept connections as root and then pass them off to non-root handler processes with
SCM_RIGHTS
.I’m not sure the echo server works correctly. How is eof detected? A control-d prints a bunch of newlines.
The implementation has a bug, and doesn’t account for end-of-file. The method call
client.gets
will returnnil
after EOF; the program should check for that. There is a pull request to fix that on GitHub.networking tag?
Lol, and I forgive you.