Update 2017:
Disclaimer (update per 2021): Note that authbind
works via LD_PRELOAD
, which is only used if your program uses libc
, which is (or might) not be the case if your program is compiled with GO, or any other compiler that avoids C. If you use go, set the kernel parameter for the protected port range, see bottom of post. </EndUpdate>
Authbind
is much better than CAP_NET_BIND_SERVICE
or a custom kernel.
CAP_NET_BIND_SERVICE
grants trust to the binary but provides no
control over per-port access.
Authbind
grants trust to the
user/group and provides control over per-port access, and
supports both IPv4 and IPv6 (IPv6 support has been added as of late).
Install: apt-get install authbind
Configure access to relevant ports, e.g. 80 and 443 for all users and groups:
sudo touch /etc/authbind/byport/80
sudo touch /etc/authbind/byport/443
sudo chmod 777 /etc/authbind/byport/80
sudo chmod 777 /etc/authbind/byport/443
Execute your command via authbind
(optionally specifying --deep
or other arguments, see man authbind
):
authbind --deep /path/to/binary command line args
e.g.
authbind --deep java -jar SomeServer.jar
As a follow-up to Joshua's fabulous (=not recommended unless you know what you do) recommendation to hack the kernel:
I've first posted it here.
Simple. With a normal or old kernel, you don't.
As pointed out by others, iptables
can forward a port.
As also pointed out by others, CAP_NET_BIND_SERVICE
can also do the job.
Of course CAP_NET_BIND_SERVICE
will fail if you launch your program from a script, unless you set the cap on the shell interpreter, which is pointless, you could just as well run your service as root...
e.g. for Java, you have to apply it to the JAVA JVM
sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java
Obviously, that then means any Java program can bind system ports.
Ditto for mono/.NET.
I'm also pretty sure xinetd isn't the best of ideas.
But since both methods are hacks, why not just lift the limit by lifting the restriction ?
Nobody said you have to run a normal kernel, so you can just run your own.
You just download the source for the latest kernel (or the same you currently have).
Afterwards, you go to:
/usr/src/linux-<version_number>/include/net/sock.h:
There you look for this line
/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK 1024
and change it to:
#define PROT_SOCK 0
if you don't want to have an insecure ssh situation, you alter it to this:
#define PROT_SOCK 24
Generally, I'd use the lowest setting that you need, e.g. 79 for http, or 24 when using SMTP on port 25.
That's already all.
Compile the kernel, and install it.
Reboot.
Finished - that stupid limit is GONE, and that also works for scripts.
Here's how you compile a kernel:
https://help.ubuntu.com/community/Kernel/Compile
# You can get the kernel-source via package `linux-source`, no manual download required
apt-get install linux-source fakeroot
mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>
# Apply the changes to PROT_SOCK define in /include/net/sock.h
# Copy the kernel config file you are currently using
cp -vi /boot/config-`uname -r` .config
# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev
# Run menuconfig (optional)
make menuconfig
# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers
# And wait a long long time
cd ..
In a nutshell:
- use
iptables
if you want to stay secure,
- compile the kernel if you want to be sure this restriction never bothers you again.
sysctl method
Note:
As of late, updating the kernel is no longer required.
You can now set:
sysctl net.ipv4.ip_unprivileged_port_start=80
Or to persist:
sysctl -w net.ipv4.ip_unprivileged_port_start=80
And if that yields an error, simply edit /etc/sysctl.conf
with nano and set the parameter there for persistence across reboots.
or via procfs
echo 80 | sudo tee /proc/sys/net/ipv4/ip_unprivileged_port_start