TUN/TAP device in lxc containers

To create tun/tap devices in Red Hat or Debian based distros inside lxc containers, create the following systemd unit:

/etc/systemd/system/tundev.service:
    [Unit]
    Description=Add tun device workaround
    Wants=network.target
 
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/usr/bin/mkdir /dev/net
    ExecStart=/usr/bin/mknod -m 666 /dev/net/tun c 10 200
 
    [Install]
    WantedBy=multi-user.target

To create the tun/tap device before certain units start (ex. OpenVpn) you can add

Before=openvpn@.service

under [Unit].

To allow the container to create the device, the following line must be in the lxc config file (/var/lib/lxc/100/config):

lxc.cgroup.devices.allow = c 10:200 rwm

For Proxmox, add the following line to the container config (ex. /etc/pve/lxc/100.conf):

lxc.cgroup.devices.allow: c 10:200 rwm
Advertisements
TUN/TAP device in lxc containers

Simple VPN network mesh with tinc

From Wikipedia:

Tinc is an open-source, self-routing, mesh networking protocol, used for compressed, encrypted, virtual private networks.

Network graph:

tinc mesh

 

Hosts:

storage-01:

public ip:   123.123.123.100
vpn ip:      10.0.0.1
connects to: media01, router01

media-01:

public ip:   123.123.123.200
vpn ip:      10.0.0.2
connects to: storage01, router01

router-01:

public ip:   123.123.123.300
vpn ip:      10.0.0.3
connects to: storage01, media01

Note: Using dashes (-) in tinc hostname files does not work.

VPN name:

myvpn

tinc setup:

Identical directory tree on all servers after setup:

/etc/tinc/
└── myvpn
     ├── hosts
     │   ├── media01
     │   ├── router01
     │   └── storage01
     ├── rsa_key.priv
     ├── tinc.conf
     ├── tinc-down
     └── tinc-up

storage-01 (centos 7):

# Install tinc
yum install tinc -y

# Create directories
mkdir -p /etc/tinc/myvpn/hosts/

/etc/tinc/myvpn/hosts/storage01:
    Address = 123.123.123.100
    Subnet = 10.0.0.1/32
    
/etc/tinc/myvpn/tinc.conf:
    Name = storage01
    Interface = tun8
    AddressFamily = ipv4
    ConnectTo = router01
    ConnectTo = media01

/etc/tinc/myvpn/tinc-up:
    #!/bin/sh
    ip link set $INTERFACE up
    ip addr add 10.0.0.1/32 dev $INTERFACE
    ip route add 10.0.0.0/24 dev $INTERFACE

/etc/tinc/myvpn/tinc-down:
    #!/bin/sh
    ip route del 10.0.0.0/24 dev $INTERFACE
    ip addr del 10.0.0.1/32 dev $INTERFACE
    ip link set $INTERFACE down

media-01 (centos 7):

# Install tinc
yum install tinc -y

# Create directories
mkdir -p /etc/tinc/myvpn/hosts/

/etc/tinc/myvpn/hosts/media01:
    Address = 123.123.123.200
    Subnet = 10.0.0.2/32

/etc/tinc/myvpn/tinc.conf:
    Name = media01
    Interface = tun8
    AddressFamily = ipv4
    ConnectTo = storage01
    ConnectTo = router01

/etc/tinc/myvpn/tinc-up:
    #!/bin/sh
    ip link set $INTERFACE up
    ip addr add 10.0.0.2/32 dev $INTERFACE
    ip route add 10.0.0.0/24 dev $INTERFACE

/etc/tinc/myvpn/tinc-down:
    #!/bin/sh
    ip route del 10.0.0.0/24 dev $INTERFACE
    ip addr del 10.0.0.2/32 dev $INTERFACE
    ip link set $INTERFACE down

router-01 (centos 7):

# Install tinc
yum install tinc -y

# Create directories
mkdir -p /etc/tinc/myvpn/hosts/
    
/etc/tinc/myvpn/hosts/router01:
    Address = 123.123.123.300
    Subnet = 10.0.0.3/32
    
/etc/tinc/myvpn/tinc.conf:
    Name = router01
    Interface = tun8
    AddressFamily = ipv4
    ConnectTo = storage01
    ConnectTo = media01

/etc/tinc/myvpn/tinc-up:
    #!/bin/sh
    ip link set $INTERFACE up
    ip addr add 10.0.0.3/32 dev $INTERFACE
    ip route add 10.0.0.0/24 dev $INTERFACE

/etc/tinc/myvpn/tinc-down:
    ip route del 10.0.0.0/24 dev $INTERFACE
    ip addr del 10.0.0.3/32 dev $INTERFACE
    ip link set $INTERFACE down

On all servers:

# Create private/public keypair
tincd -n myvpn -K4096

/etc/firewalld/services/tinc.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <service>
        <short>tinc</short>
        <description>tinc VPN daemon</description>
        <port protocol="udp" port="655"/>
        <port protocol="tcp" port="655"/>
    </service>

firewall-cmd --add-service=tinc --permanent
firewall-cmd --reload

All servers should have a copy of all host files with the public keys, so copy them.

[root@media-01 ~]# rsync /etc/tinc/myvpn/hosts/ router-01:/etc/tinc/myvpn/hosts/ -av
[root@media-01 ~]# rsync /etc/tinc/myvpn/hosts/ storage-01:/etc/tinc/myvpn/hosts/ -av
[root@router-01 ~]# rsync /etc/tinc/myvpn/hosts/ media-01:/etc/tinc/myvpn/hosts/ -av 
[root@router-01 ~]# rsync /etc/tinc/myvpn/hosts/ storage-01:/etc/tinc/myvpn/hosts/ -av
[root@storage-01 ~]# rsync /etc/tinc/myvpn/hosts/ media-01:/etc/tinc/myvpn/hosts/ -av
[root@storage-01 ~]# rsync /etc/tinc/myvpn/hosts/ router-01:/etc/tinc/myvpn/hosts/ -av

On all servers:

# Set executable bit on tinc-up and tinc-down
chmod +x /etc/tinc/myvpn/tinc-up
chmod +x /etc/tinc/myvpn/tinc-down
# Enable and start tinc:
systemctl enable tinc@myvpn
systemctl start tinc@myvpn

Now all three servers should be able to communicate on 10.0.0.0/24.
If communication between any two drops, it’ll route through the third one.

Note on Debian 8:

Debian 8 dosen’t have a systemd unit for tinc yet, so to get tinc up and running /etc/tinc/nets.boot should contain names of all networks to be started. You can then start it normally with init/systemd.

For example:

/etc/tinc/
 ├── myvpn
 │   ├── hosts
 │   │   ├── media01
 │   │   ├── router01
 │   │   ├── storage01
 │   ├── rsa_key.priv
 │   ├── tinc.conf
 │   ├── tinc-down
 │   └── tinc-up
 └── nets.boot
/etc/tinc/nets.boot:
    myvpn
# Enable and start tinc
systemctl enable tinc
systemctl start tinc

# Check the status
systemctl status tinc
Simple VPN network mesh with tinc

iodine client/server on CentOS 7

From http://code.kryo.se/iodine/:

iodine lets you tunnel IPv4 data through a DNS server. This can be usable in different situations where internet access is firewalled, but DNS queries are allowed.

DNS Setup

Name     Type    Value            
iodine   NS      tunnel.domain.com
tunnel   A       123.123.123.123

Server:

Install:

yum install iodine-server -y

Configure iodine-server.service in “/etc/sysconfig/iodine-server”:

OPTIONS="-f -P 'good password' 172.21.21.1/24 iodine.domain.com"

where 172.21.21.1/24 is the tunnel ip/netmask

Start the server:

[root@iodine ~]# systemctl start iodine-server.service
[root@iodine ~]# systemctl status iodine-server.service
iodine-server.service - Iodine Server
 Loaded: loaded (/usr/lib/systemd/system/iodine-server.service; enabled)
 Active: active (running) since Sat 2015-06-20 02:24:28 GMT; 42s ago
 Main PID: 1960 (iodined)
 CGroup: /system.slice/iodine-server.service
 └─1960 /usr/sbin/iodined -f -P 172.21.21.1 24 iodine.domain.com

Jun 20 02:24:28 iodine.domain.com systemd[1]: Starting Iodine Server...
Jun 20 02:24:28 iodine.domain.com systemd[1]: Started Iodine Server.
Jun 20 02:24:28 iodine.domain.com iodined[1960]: Opened dns0
Jun 20 02:24:28 iodine.domain.com iodined[1960]: Setting IP of dns0 to 172.21.21.1
Jun 20 02:24:28 iodine.domain.com iodined[1960]: Setting MTU of dns0 to 1130
Jun 20 02:24:28 iodine.domain.com iodined[1960]: Opened IPv4 UDP socket
Jun 20 02:24:28 iodine.domain.com iodined[1960]: Listening to dns for domain iodine.domain.com
Jun 20 02:24:28 iodine.domain.com iodined[1960]: started, listening on port 53

Enable IPv4 forwarding in the kernel:

echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.d/99-sysctl.conf
sysctl -p /etc/sysctl.d/99-sysctl.conf

Client:

Install:

yum install iodine-client

Configure iodine-client.service in “/etc/sysconfig/iodine-client”:

iodine -f -r 123.123.123.123 iodine.domain.com -P 'good password'

Start the client:

[root@iodine-client ~]# systemctl start iodine-client
[root@iodine-client ~]# systemctl status iodine-client
iodine-client.service - Iodine Client
 Loaded: loaded (/usr/lib/systemd/system/iodine-client.service; disabled)
 Active: active (running) since Sat 2015-06-20 02:27:46 GMT; 3s ago
 Main PID: 2020 (iodine)
 CGroup: /system.slice/iodine-client.service
 └─2020 /usr/sbin/iodine -f -r 123.123.123.123 iodine.domain.com -P

Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: Using EDNS0 extension
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: Switching upstream to codec Base128
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: Server switched upstream to codec Base128
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: No alternative downstream codec available, using default (Raw)
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: Switching to lazy mode for low-latency
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: Server switched to lazy mode
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: Autoprobing max downstream fragment size... (skip with -m fragsize)
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: 768 ok.. 1152 ok.. 1344 ok.. 1440 ok.. 1488 ok.. 1512 ok.. 1524 ok.. will use 1524-2=1522
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: Setting downstream fragment size to max 1522...
Jun 20 02:27:46 iodine-client.domain.com iodine[2020]: Connection setup complete, transmitting data.

Test client -> server and server -> client ping:

[root@iodine-client ~]# ping 172.21.21.1
PING 172.21.21.1 (172.21.21.1) 56(84) bytes of data.
64 bytes from 172.21.21.1: icmp_seq=1 ttl=64 time=0.045 ms
64 bytes from 172.21.21.1: icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from 172.21.21.1: icmp_seq=3 ttl=64 time=0.038 ms
64 bytes from 172.21.21.1: icmp_seq=4 ttl=64 time=0.057 ms
^C
--- 172.21.21.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.038/0.048/0.057/0.010 ms
[root@iodine-client ~]#
[root@iodine ~]# ping 172.21.21.2
PING 172.21.21.2 (172.21.21.2) 56(84) bytes of data.
64 bytes from 172.21.21.2: icmp_seq=1 ttl=64 time=0.063 ms
64 bytes from 172.21.21.2: icmp_seq=2 ttl=64 time=0.062 ms
64 bytes from 172.21.21.2: icmp_seq=3 ttl=64 time=0.064 ms
64 bytes from 172.21.21.2: icmp_seq=4 ttl=64 time=0.057 ms
^C
--- 172.21.21.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.057/0.061/0.064/0.008 ms
[root@iodine ~]#

Example of an ssh tunnel (socks proxy) through the iodine server:

ssh 172.21.21.1 -p 443 -D 8080 -f -N

Or if you are using the iodine NetworkManager plugin:

dnf install NetworkManager-iodine-gnome -y

Screenshot from 2015-06-20 01-58-57

Screenshot from 2015-06-20 01-59-14

Screenshot from 2015-06-20 02-00-44

Screenshot from 2015-06-20 02-02-43

Screenshot from 2015-06-20 02-02-48

 

iodine GitHub: https://github.com/yarrick/iodine

 

iodine client/server on CentOS 7