Hi everyone,
The following patch makes it possible to build SSH layer 2 (and layer
3) tunnels without using root permissions when connecting.
This is achieved by root setting up everything beforehand so sshd
doesn't have to do it. However, the old functionality of sshd setting
things up with root permissions is preserved.
What my patch does is:
1. Check the current value of network interface parameters
2. If change is needed try to do it:
* Fail like it failed before if no permissions
* Or set the parameters and proceed like before
3. If no changes needed just continue without fail.
After the patch is applied and sshd is rebuilt, installed and
restarted one can set up SSH layer 2 tunnel server as follows:
* groupadd tunnel
* useradd -m -c "Test User" -G tunnel test
* chown :tunnel /dev/tun? && chmod g+rw /dev/tun?
* for i in 0 1 2 3; do printf "create\nlink0\nup\n" >/etc/hostname.tun$i; done
* for i in 0 1 2 3; do sh /etc/netstart tun$i; done
Now things should look like this:
* ls -l /dev/tun0
crw-rw---- 1 root tunnel 40, 0 Sep 18 14:52 /dev/tun0
* ifconfig tun0
tun0: flags=9803<UP,BROADCAST,SIMPLEX,LINK0,MULTICAST> mtu 1500
lladdr fe:e1:ba:d1:6b:94
priority: 0
groups: tun
status: no carrier
Last, config sshd to allow tunnels:
* echo "PermitTunnel ethernet" >>/etc/ssh/sshd_config
* kill -HUP `cat /var/run/sshd.pid`
And connect from client (client needs permissions, check yours):
* ssh -w any -o Tunnel=ethernet [email protected]
Is this patch the correct way of achieving what's described above?
Thanks,
Ossi Herrala
Index: usr.bin/ssh/misc.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/misc.c,v
retrieving revision 1.97
diff -u -p -r1.97 misc.c
--- usr.bin/ssh/misc.c 24 Apr 2015 01:36:00 -0000 1.97
+++ usr.bin/ssh/misc.c 18 Sep 2015 14:08:27 -0000
@@ -664,19 +664,21 @@ tun_open(int tun, int mode)
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
goto failed;
- /* Set interface mode */
- ifr.ifr_flags &= ~IFF_UP;
- if (mode == SSH_TUNMODE_ETHERNET)
- ifr.ifr_flags |= IFF_LINK0;
- else
- ifr.ifr_flags &= ~IFF_LINK0;
- if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
- goto failed;
+ if (((mode == SSH_TUNMODE_ETHERNET) && !(ifr.ifr_flags & IFF_LINK0)) ||
+ ((mode != SSH_TUNMODE_ETHERNET) && ifr.ifr_flags & IFF_LINK0)) {
+ /* Set interface mode */
+ ifr.ifr_flags &= ~IFF_UP;
+ ifr.ifr_flags ^= IFF_LINK0;
+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
+ goto failed;
+ }
- /* Bring interface up */
- ifr.ifr_flags |= IFF_UP;
- if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
- goto failed;
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ /* Bring interface up */
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
+ goto failed;
+ }
close(sock);
return (fd);