Archive

Last modified by Administrator on 2022/01/30 10:10

Blog - posts for September 2014

Sep 01 2014

Tunnelling through the Internet

As mentioned in the previous post, I'm writing down some details concerning setting up a VPN, which can occasionally be quite useful, whether it be due to accessing the Internet from an insecure location or due to working around region restrictions. As before, I'm using Libreswan, along with xl2tpd and ppp. I'm also using winbind (part of the Samba project) in order to authenticate against a Windows domain.

VPN

Bits and pieces taken from this page.

As with the subnet-to-subnet configuration, you'll need to put the Libreswan repository file in /etc/yum.repos.d, put the the Libreswan GPG key in /etc/pki/rpm-gpg, and install the Fedora Extra Packages for Enterprise Linux 6 RPM. At this point, you can install the packages you need to move forward:

$ yum install libreswan xl2tpd ppp

There are more moving pieces this time through, so the configuration is a bit more involved. Our example uses the following assumptions:

192.168.0.0/24: internal network
1.2.3.4: external network IP
192.168.0.1: internal network IP
192.168.0.200: internal network DNS IP
192.168.0.90-192.168.0.99: IP range for VPN clients
eth0: external-facing network adapter
eth1: internal-facing network adapter

Libreswan

Configure /etc/ipsec.conf as noted in the previous article. We'll set up another configuration file for the dialin VPN, /etc/ipsec.d/dialin.conf. For the sake of simplicity (and compatibility), we'll do a pre-shared key (PSK) configuration:

/etc/ipsec.d/dialin.conf
conn dialin
       # We're using a PSK for now.
       authby=secret
       # Add the VPN type, but don't start it (since clients will be initiating connections).
       auto=add
       forceencaps=yes
       ike_frag=yes
       # The outside-facing IP.
       left=1.2.3.4
       leftid=@left.internal
       leftsubnet=0.0.0.0/0
       right=%any
       rightsubnet=0.0.0.0/0
       # The internal DNS server's IP.
       modecfgdns1=192.168.0.100
       modecfgpull=yes
       pfs=no
       rekey=no

To define the PSK, create /etc/ipsec.d/dialin.secrets:

/etc/ipsec.d/dialin.secrets
# As before, the outside-facing IP. Also, change the PSK to something considerably better than this.
1.2.3.4  %any  :  PSK "pre-shared key"

As before, you can be paranoid with the secrets file:

$ chown root:root /etc/ipsec.d/*.secrets
$ chmod 0600 /etc/ipsec.d/*.secrets

And the same additional lines to /etc/sysctl.conf apply here:

/etc/sysctl.conf
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0

Along with the verification step:

$ ipsec verify

xl2tpd/ppp

xl2tpd and ppp are intertwined, so their configuration happens pretty much at the same time. Set up your /etc/xl2tpd/xl2tpd.conf roughly as follows, adjusting for the configuration above:

/etc/xl2tpd/xl2tpd.conf
[global]
listen-addr = 1.2.3.4

[lns default]
ip range = 192.168.0.90-192.168.0.99
local ip = 192.168.0.1
require chap = yes
refuse pap = yes
require authentication = yes
name = l2tpd
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes

For now, set up /etc/ppp/options.xl2tpd as follows:

/etc/ppp/options.xl2tpd
ipcp-accept-local
ipcp-accept-remote
ms-dns 192.168.0.200
noccp
auth
crtscts
idle 1800
mtu 1410
mru 1410
nodefaultroute
lock
proxyarp
connect-delay 5000

Set up usernames and passwords in /etc/ppp/chap-secrets, one per line (replace $username and $password as appropriate):

/etc/ppp/chap-secrets
$username l2tpd "$password" *

iptables

As before, there need to be additional entries in the iptables configuration:

iptables
# Set up an ICMP bucket.
-N ICMPALL
# Set up a rejection bucket.
-N ZREJ

# Using connection tracking, accept packets we already know about.
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Trust the local network; you can choose to have more restrictive rules than this.
-A INPUT -i eth1 -j ACCEPT
-A INPUT -i ppp+ -j ACCEPT
-A FORWARD -i eth1 -j ACCEPT
-A FORWARD -i ppp+ -j ACCEPT

# Treat ICMP packets specially.
-A INPUT -p icmp -m icmp --icmp-type any -j ICMPALL

# Allow new connections to be made to ports 500 (IKE) and 4500 (IKE NAT-Traversal), both for Libreswan.
-A INPUT -p udp -m conntrack --ctstate NEW -m multiport --dports 500,4500 -j ACCEPT

# Allow connections to port 1701 (L2TP) for Libreswan.
-A INPUT -p udp -m udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT
-A INPUT -p udp -m udp --dport 1701 -j DROP

# Goes at the bottom of the INPUT section: reject all other packets.
-A INPUT -j ZREJ

# Only forward connections we know about from the "outside" to the "inside," using built-in connection tracking.
-A FORWARD -i eth0 -o eth1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth0 -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Forward valid IPsec packets.
-A FORWARD -m policy --dir in --pol ipsec -j ACCEPT

# Goes at the bottom of the FORWARD section: reject all other packets.
-A FORWARD -j ZREJ

# Reject fragmented packets.
-A ICMPALL -p icmp -f -j DROP
# Accept: echo reply
-A ICMPALL -p icmp -m icmp --icmp-type 0 -j ACCEPT
# Accept: destination unreachable
-A ICMPALL -p icmp -m icmp --icmp-type 3 -j ACCEPT
# Accept: source quench
-A ICMPALL -p icmp -m icmp --icmp-type 4 -j ACCEPT
# Accept: echo
-A ICMPALL -p icmp -m icmp --icmp-type 8 -j ACCEPT
# Accept: time exceeded
-A ICMPALL -p icmp -m icmp --icmp-type 11 -j ACCEPT
# Drop all other ICMP packets.
-A ICMPALL -p icmp -j DROP

# Reject packet types as appropriate.
-A ZREJ -p tcp -j REJECT --reject-with tcp-reset
-A ZREJ -p udp -j REJECT --reject-with icmp-port-unreachable
-A ZREJ -j REJECT --reject-with icmp-proto-unreachable

Testing the VPN

At this point, you can set up the VPN from a client, with the following settings:

  • Host: 1.2.3.4
  • Type: L2TP/IPsec
    • Pre-shared key (not a certificate): the key defined above
    • Protocol: CHAP (not MS-CHAP v2)
  • Username: a username defined above
  • Password: a password defined above

You should be able to connect successfully, and connect to systems within the internal network at this point. If you are using a Windows system behind a NAT, you may need to set a registry setting and reboot your system prior to being able to connect to the VPN.

Connecting to a Windows domain

The way pppd works on Linux, authenticating against LDAP involves connecting the ppp daemon to RADIUS, then allowing RADIUS to validate credentials against LDAP. Unfortunately, RADIUS performs the validation itself, so it requires authenticating against the VPN server with PAP and storing plaintext passwords within LDAP, which is less than ideal. There is, however, a provision to allow pppd to authenticate against a Windows domain.

First, install winbind:

$ yum install samba-winbind

Set up your /etc/samba/smb.conf with the appropriate information (change the following settings to match those for your own domain):

/etc/samba/smb.conf
[global]
 # Must be all capitals. Adjust to your domain's NetBIOS name.
 workgroup = INTERNAL
 # Adjust to your system's desired NetBIOS name.
 netbios name = VPN
 interfaces = lo eth1
 bind interfaces only = true
 security = ads
 # Must be all capitals. Adjust to your domain's FQDN.
 realm = INTERNAL.LOCAL
 # Set to your domain's PDC.
 password server = pdc.internal.local pdc
  winbind uid = 500-20000
  winbind gid = 500-20000
  winbind enum users = yes
  winbind enum groups = yes
  winbind use default domain = yes

Then, there are several commands to complete the domain setup:

# Restart winbind.
$ service winbind restart
# Join the system to the domain.
$ net ads join -U Administrator
# See whether it's joined.
$ net ads testjoin
# Verify that it's joined by displaying the user list.
$ wbinfo -u

You can clear out the entries from /etc/ppp/chap-secrets, as you won't be using the passwords stored in a text file. Update the following settings in /etc/xl2tpd/xl2tpd.conf:

/etc/xl2tpd/xl2tpd.conf
; Comment out the following line.
; require chap = yes
refuse chap = yes

And the following settings in /etc/ppp/options.xl2tpd:

/etc/ppp/options.xl2tpd
# Replace with your domain controllers.
ms-dns  10.0.0.250

# Add these lines.
require-mschap-v2
require-mppe-128
plugin winbind.so

# Set the following line with the group that controls the list of VPN users.
ntlm_auth-helper '/usr/bin/ntlm_auth --helper-protocol=ntlm-server-1 --require-membership-of="INTERNAL\\VPN Users"'

If you have SELinux enabled, you'll need to generate a policy to allow ntlm_auth to run. You can follow the instructions on this page to figure out how to do so. Your template file should look something like this:

ntlm_auth.te
module winbind_helper 1.0;

require {
       type pppd_t;
       type winbind_helper_exec_t;
        class file { read execute open getattr execute_no_trans };
}

#============= pppd_t ==============
allow pppd_t winbind_helper_exec_t:file execute_no_trans;

#!!!! This avc is allowed in the current policy
allow pppd_t winbind_helper_exec_t:file { read execute open getattr };

The end of the line

Ideally, we would go through and implement user authentication via domain username and password (as above) with machine authentication via certificates. Unfortunately, at least one of the targeted operating systems doesn't support machine certificates for L2TP/IPsec, so there isn't too much value in pursuing it further.