mirror of
https://github.com/teddysun/across.git
synced 2025-01-19 06:19:35 +08:00
Added L2TP/IPSec VPN Server Docker Image
Signed-off-by: Teddysun <i@teddysun.com>
This commit is contained in:
parent
686fd98b77
commit
890f0473c0
3
docker/l2tp/.dockerignore
Normal file
3
docker/l2tp/.dockerignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.dockerignore
|
||||||
|
README.md
|
||||||
|
l2tp.env
|
25
docker/l2tp/Dockerfile
Normal file
25
docker/l2tp/Dockerfile
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Dockerfile for L2TP/IPSec VPN Server
|
||||||
|
# Copyright (C) 2018 Teddysun <i@teddysun.com>
|
||||||
|
|
||||||
|
FROM debian:stretch
|
||||||
|
MAINTAINER Teddysun <i@teddysun.com>
|
||||||
|
|
||||||
|
RUN set -ex \
|
||||||
|
&& printf "deb http://deb.debian.org/debian sid main" > /etc/apt/sources.list.d/sid.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get -t sid install -y --no-install-recommends libreswan xl2tpd \
|
||||||
|
&& apt-get install -y --no-install-recommends wget iproute2 openssl ca-certificates kmod net-tools iptables \
|
||||||
|
&& apt-get -y autoremove \
|
||||||
|
&& apt-get -y clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY ./ipsec /etc/init.d/ipsec
|
||||||
|
COPY ./l2tp.sh /usr/bin/l2tp
|
||||||
|
COPY ./l2tpctl.sh /usr/bin/l2tpctl
|
||||||
|
RUN chmod 755 /etc/init.d/ipsec /usr/bin/l2tp /usr/bin/l2tpctl
|
||||||
|
|
||||||
|
VOLUME /lib/modules
|
||||||
|
|
||||||
|
EXPOSE 500/udp 4500/udp
|
||||||
|
|
||||||
|
CMD [ "/usr/bin/l2tp" ]
|
128
docker/l2tp/README.md
Normal file
128
docker/l2tp/README.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
## L2TP/IPsec VPN Server Docker Image by Teddysun
|
||||||
|
|
||||||
|
Docker image to run a L2TP/IPsec VPN Server, with both `L2TP/IPsec PSK` and `IPSec Xauth PSK`.
|
||||||
|
Based on Debian 9 (Stretch) with latest libreswan (IPsec VPN software) and xl2tpd (L2TP daemon).
|
||||||
|
|
||||||
|
Docker images are built for quick deployment in various computing cloud providers.
|
||||||
|
For more information on docker and containerization technologies, refer to [official document][1].
|
||||||
|
|
||||||
|
## Prepare the host
|
||||||
|
|
||||||
|
If you need to install docker by yourself, follow the [official installation guide][2].
|
||||||
|
|
||||||
|
## Pull the image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker pull teddysun/l2tp
|
||||||
|
```
|
||||||
|
|
||||||
|
This pulls the latest release of shadowsocks-libev.
|
||||||
|
It can be found at [Docker Hub][3].
|
||||||
|
|
||||||
|
## Start a container
|
||||||
|
|
||||||
|
You **must create a environment file** `/etc/l2tp.env` in host at first, and sample value is below:
|
||||||
|
|
||||||
|
```
|
||||||
|
VPN_IPSEC_PSK=teddysun.com
|
||||||
|
VPN_USER=vpnuser
|
||||||
|
VPN_PASSWORD=vpnpassword
|
||||||
|
VPN_PUBLIC_IP=
|
||||||
|
VPN_L2TP_NET=
|
||||||
|
VPN_L2TP_LOCAL=
|
||||||
|
VPN_L2TP_REMOTE=
|
||||||
|
VPN_XAUTH_NET=
|
||||||
|
VPN_XAUTH_REMOTE=
|
||||||
|
VPN_DNS1=
|
||||||
|
VPN_DNS2=
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a default user account for L2TP/IPsec VPN login, which can be used by your **multiple devices**.
|
||||||
|
The IPSec PSK (pre-shared key) is specified by the `VPN_IPSEC_PSK` environment variable.
|
||||||
|
The username is specified in `VPN_USER` environment variable.
|
||||||
|
and password is specified in `VPN_PASSWORD` environment variable.
|
||||||
|
If your VPS has multiple public IP addresses, maybe public IP need to specified in `VPN_PUBLIC_IP` environment variable.
|
||||||
|
|
||||||
|
There is an example to start a container:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker run -d --privileged -p 500:500/udp -p 4500:4500/udp --name l2tp --env-file /etc/l2tp.env -v /lib/modules:/lib/modules teddysun/l2tp
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: The UDP port number `500` and `4500` must be opened in firewall.
|
||||||
|
|
||||||
|
## Check container details
|
||||||
|
|
||||||
|
If you want to view the container logs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker logs l2tp
|
||||||
|
```
|
||||||
|
|
||||||
|
Output log like below:
|
||||||
|
|
||||||
|
```
|
||||||
|
L2TP/IPsec VPN Server with the Username and Password is below:
|
||||||
|
|
||||||
|
Server IP: Your Server public IP
|
||||||
|
IPSec PSK: IPSec PSK (pre-shared key)
|
||||||
|
Username : VPN username
|
||||||
|
Password : VPN password
|
||||||
|
|
||||||
|
Redirecting to: /etc/init.d/ipsec start
|
||||||
|
Starting pluto IKE daemon for IPsec: Initializing NSS database
|
||||||
|
|
||||||
|
xl2tpd[1]: Not looking for kernel SAref support.
|
||||||
|
xl2tpd[1]: Using l2tp kernel support.
|
||||||
|
xl2tpd[1]: xl2tpd version xl2tpd-1.3.12 started on 1d20eaecd9f2 PID:1
|
||||||
|
xl2tpd[1]: Written by Mark Spencer, Copyright (C) 1998, Adtran, Inc.
|
||||||
|
xl2tpd[1]: Forked by Scott Balmos and David Stipp, (C) 2001
|
||||||
|
xl2tpd[1]: Inherited by Jeff McAdams, (C) 2002
|
||||||
|
xl2tpd[1]: Forked again by Xelerance (www.xelerance.com) (C) 2006-2016
|
||||||
|
xl2tpd[1]: Listening on IP address 0.0.0.0, port 1701
|
||||||
|
```
|
||||||
|
|
||||||
|
To check the status of your L2TP/IPSec VPN server, you can confirm `ipsec status` to your container like below:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker exec -it l2tp ipsec status
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manage VPN Users
|
||||||
|
|
||||||
|
If you want to add, modify or remove user accounts, please do it simple like below:
|
||||||
|
|
||||||
|
### List all users
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker exec -it l2tp l2tpctl -l
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add a user
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker exec -it l2tp l2tpctl -a
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delete a user
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker exec -it l2tp l2tpctl -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modify a user password
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker exec -it l2tp l2tpctl -m
|
||||||
|
```
|
||||||
|
|
||||||
|
### Print help information
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker exec -it l2tp l2tpctl -h
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
[1]: https://docs.docker.com/
|
||||||
|
[2]: https://docs.docker.com/install/
|
||||||
|
[3]: https://hub.docker.com/r/teddysun/l2tp/
|
304
docker/l2tp/ipsec
Normal file
304
docker/l2tp/ipsec
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# IPsec startup and shutdown script
|
||||||
|
#
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: ipsec
|
||||||
|
# Required-Start: $network $remote_fs $syslog $named
|
||||||
|
# Required-Stop: $syslog $remote_fs
|
||||||
|
# Default-Start:
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: Start Libreswan IPsec at boot time
|
||||||
|
# Description: Enable automatic key management for IPsec (KLIPS and NETKEY)
|
||||||
|
### END INIT INFO
|
||||||
|
#
|
||||||
|
### see https://bugzilla.redhat.com/show_bug.cgi?id=636572
|
||||||
|
### Debian and Fedora interpret the LSB differently for Default-Start:
|
||||||
|
|
||||||
|
# Copyright (C) 1998, 1999, 2001 Henry Spencer.
|
||||||
|
# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
|
||||||
|
# Copyright (C) 2006 Michael Richardson <mcr@xelerance.com>
|
||||||
|
# Copyright (C) 2008 Michael Richardson <mcr@sandelman.ca>
|
||||||
|
# Copyright (C) 2008-2015 Tuomo Soini <tis@foobar.fi>
|
||||||
|
# Copyright (C) 2012 Paul Wouters <paul@libreswan.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
# for more details.
|
||||||
|
#
|
||||||
|
# ipsec sysv style init.d script for starting and stopping
|
||||||
|
# the IPsec security subsystem (KLIPS and Pluto).
|
||||||
|
#
|
||||||
|
# This script becomes /etc/init.d/ipsec
|
||||||
|
# and is also accessible as "ipsec setup"
|
||||||
|
#
|
||||||
|
# The startup and shutdown times are a difficult compromise (in particular,
|
||||||
|
# it is almost impossible to reconcile them with the insanely early/late
|
||||||
|
# times of NFS filesystem startup/shutdown). Startup is after startup of
|
||||||
|
# syslog and pcmcia support; shutdown is just before shutdown of syslog.
|
||||||
|
#
|
||||||
|
# chkconfig: - 47 76
|
||||||
|
# description: IPsec provides encrypted and authenticated communications; \
|
||||||
|
# NETKEY/KLIPS is the kernel half of it, Pluto is the user-level management daemon.
|
||||||
|
|
||||||
|
test ${IPSEC_INIT_SCRIPT_DEBUG} && set -v -x
|
||||||
|
|
||||||
|
# Source function library.
|
||||||
|
if [ -f /etc/init.d/functions ]; then
|
||||||
|
. /etc/init.d/functions
|
||||||
|
elif [ -f /lib/lsb/init-functions ]; then
|
||||||
|
. /lib/lsb/init-functions
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check that networking is up.
|
||||||
|
[ "${NETWORKING}" = "no" ] && exit 6
|
||||||
|
|
||||||
|
if [ $(id -u) -ne 0 ]; then
|
||||||
|
echo "permission denied (must be superuser)" | \
|
||||||
|
logger -s -p daemon.error -t ipsec_setup 2>&1
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $(ip addr list | grep -c cipsec) -ne 0 ]; then
|
||||||
|
echo "Cisco IPsec client is already loaded, aborting! (cipsec# device found)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# where the private directory and the config files are
|
||||||
|
IPSEC_CONF="${IPSEC_CONF:-/etc/ipsec.conf}"
|
||||||
|
IPSEC_EXECDIR="${IPSEC_EXECDIR:-/usr/lib/ipsec}"
|
||||||
|
IPSEC_SBINDIR="${IPSEC_SBINDIR:-/usr/sbin}"
|
||||||
|
unset PLUTO_OPTIONS
|
||||||
|
|
||||||
|
rundir=/var/run/pluto
|
||||||
|
plutopid=${rundir}/pluto.pid
|
||||||
|
plutoctl=${rundir}/pluto.ctl
|
||||||
|
lockdir=/var/lock/subsys
|
||||||
|
lockfile=${lockdir}/ipsec
|
||||||
|
ipsecversion=/proc/net/ipsec_version
|
||||||
|
kamepfkey=/proc/net/pfkey
|
||||||
|
|
||||||
|
# /etc/resolv.conf related paths
|
||||||
|
LIBRESWAN_RESOLV_CONF=${rundir}/libreswan-resolv-conf-backup
|
||||||
|
ORIG_RESOLV_CONF=/etc/resolv.conf
|
||||||
|
|
||||||
|
# there is some confusion over the name - just do both
|
||||||
|
[ -f /etc/sysconfig/ipsec ] && . /etc/sysconfig/ipsec
|
||||||
|
[ -f /etc/sysconfig/pluto ] && . /etc/sysconfig/pluto
|
||||||
|
|
||||||
|
# misc setup
|
||||||
|
umask 022
|
||||||
|
|
||||||
|
# standardize PATH, and export it for everything else's benefit
|
||||||
|
PATH="${IPSEC_SBINDIR}:/sbin:/usr/sbin:/usr/local/bin:/bin:/usr/bin"
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
mkdir -p ${rundir}
|
||||||
|
chmod 700 ${rundir}
|
||||||
|
|
||||||
|
verify_config() {
|
||||||
|
[ -f ${IPSEC_CONF} ] || exit 6
|
||||||
|
|
||||||
|
config_error=$(ipsec addconn --config ${IPSEC_CONF} --checkconfig 2>&1)
|
||||||
|
RETVAL=$?
|
||||||
|
if [ ${RETVAL} -gt 0 ]; then
|
||||||
|
echo "Configuration error - the following error occurred:"
|
||||||
|
echo ${config_error}
|
||||||
|
echo "IKE daemon status was not modified"
|
||||||
|
exit ${RETVAL}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
echo -n "Starting pluto IKE daemon for IPsec: "
|
||||||
|
ipsec _stackmanager start
|
||||||
|
|
||||||
|
# pluto searches the current directory, so this is required for making it selinux compliant
|
||||||
|
cd /
|
||||||
|
# Create nss db or convert from old format to new sql format
|
||||||
|
ipsec --checknss
|
||||||
|
# Enable nflog if configured
|
||||||
|
ipsec --checknflog > /dev/null
|
||||||
|
# This script will enter an endless loop to ensure pluto restarts on crash
|
||||||
|
ipsec _plutorun --config ${IPSEC_CONF} --nofork ${PLUTO_OPTIONS} &
|
||||||
|
[ -d ${lockdir} ] || mkdir -p ${lockdir}
|
||||||
|
touch ${lockfile}
|
||||||
|
# Because _plutorun starts pluto at background we need to make sure pluto is started
|
||||||
|
# before we know if start was successful or not
|
||||||
|
for waitsec in 1 2 3 4 5; do
|
||||||
|
if status >/dev/null; then
|
||||||
|
RETVAL=0
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo -n "."
|
||||||
|
sleep 1
|
||||||
|
RETVAL=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ ${RETVAL} -ge 1 ]; then
|
||||||
|
rm -f ${lockfile}
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
return ${RETVAL}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
if [ -e ${plutoctl} ]; then
|
||||||
|
echo "Shutting down pluto IKE daemon"
|
||||||
|
ipsec whack --shutdown 2>/dev/null
|
||||||
|
# don't use seq, might not exist on embedded
|
||||||
|
for waitsec in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
if [ -s ${plutopid} ]; then
|
||||||
|
echo -n "."
|
||||||
|
sleep 1
|
||||||
|
else
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
rm -f ${plutoctl} # we won't be using this anymore
|
||||||
|
fi
|
||||||
|
if [ -s ${plutopid} ]; then
|
||||||
|
# pluto did not die peacefully
|
||||||
|
pid=$(cat ${plutopid})
|
||||||
|
if [ -d /proc/${pid} ]; then
|
||||||
|
kill -TERM ${pid}
|
||||||
|
RETVAL=$?
|
||||||
|
sleep 5;
|
||||||
|
if [ -d /proc/${pid} ]; then
|
||||||
|
kill -KILL ${pid}
|
||||||
|
RETVAL=$?
|
||||||
|
fi
|
||||||
|
if [ ${RETVAL} -ne 0 ]; then
|
||||||
|
echo "Kill failed - removing orphaned ${plutopid}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Removing orphaned ${plutopid}"
|
||||||
|
fi
|
||||||
|
rm -f ${plutopid}
|
||||||
|
fi
|
||||||
|
|
||||||
|
ipsec _stackmanager stop
|
||||||
|
ipsec --stopnflog > /dev/null
|
||||||
|
|
||||||
|
# cleaning up backup resolv.conf
|
||||||
|
if [ -e ${LIBRESWAN_RESOLV_CONF} ]; then
|
||||||
|
if grep 'Libreswan' ${ORIG_RESOLV_CONF} > /dev/null 2>&1; then
|
||||||
|
cp ${LIBRESWAN_RESOLV_CONF} ${ORIG_RESOLV_CONF}
|
||||||
|
fi
|
||||||
|
rm -f ${LIBRESWAN_RESOLV_CONF}
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f ${lockfile}
|
||||||
|
return ${RETVAL}
|
||||||
|
}
|
||||||
|
|
||||||
|
restart() {
|
||||||
|
verify_config
|
||||||
|
stop
|
||||||
|
start
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
status() {
|
||||||
|
local RC
|
||||||
|
if [ -f ${plutopid} ]; then
|
||||||
|
if [ -r ${plutopid} ]; then
|
||||||
|
pid=$(cat ${plutopid})
|
||||||
|
if [ -n "$pid" -a -d /proc/${pid} ]; then
|
||||||
|
RC=0 # running
|
||||||
|
else
|
||||||
|
RC=1 # not running but pid exists
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
RC=4 # insufficient privileges
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -z "${RC}" ]; then
|
||||||
|
if [ -f ${lockfile} ]; then
|
||||||
|
RC=2
|
||||||
|
else
|
||||||
|
RC=3
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
case "${RC}" in
|
||||||
|
0)
|
||||||
|
echo "ipsec: pluto (pid ${pid}) is running..."
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
echo "ipsec: pluto dead but pid file exits"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
echo "ipsec: pluto dead but subsys locked"
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
echo "ipsec: pluto status unknown due to insufficient privileges."
|
||||||
|
return 4
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "ipsec: pluto is stopped"
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
|
condrestart() {
|
||||||
|
verify_config
|
||||||
|
RETVAL=$?
|
||||||
|
if [ -f ${lockfile} ]; then
|
||||||
|
restart
|
||||||
|
RETVAL=$?
|
||||||
|
fi
|
||||||
|
return ${RETVAL}
|
||||||
|
}
|
||||||
|
|
||||||
|
version() {
|
||||||
|
ipsec version
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# do it
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
start
|
||||||
|
RETVAL=$?
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop
|
||||||
|
RETVAL=$?
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
restart
|
||||||
|
RETVAL=$?
|
||||||
|
;;
|
||||||
|
reload|force-reload)
|
||||||
|
restart
|
||||||
|
RETVAL=$?
|
||||||
|
;;
|
||||||
|
condrestart|try-restart)
|
||||||
|
condrestart
|
||||||
|
RETVAL=$?
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
status
|
||||||
|
RETVAL=$?
|
||||||
|
${IPSEC_EXECDIR}/whack --status 2>/dev/null | grep Total | sed 's/^000\ Total\ //'
|
||||||
|
;;
|
||||||
|
version)
|
||||||
|
version
|
||||||
|
RETVAL=$?
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status|version}"
|
||||||
|
RETVAL=2
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit ${RETVAL}
|
16
docker/l2tp/l2tp.env
Normal file
16
docker/l2tp/l2tp.env
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# This file is part of L2TP/IPSec VPN Server Docker image.
|
||||||
|
# Define your own values for these environment variables.
|
||||||
|
# DO NOT put "" or '' around values, or add space around =
|
||||||
|
# DO NOT use these special characters within values: \ " '
|
||||||
|
|
||||||
|
VPN_IPSEC_PSK=teddysun.com
|
||||||
|
VPN_USER=vpnuser
|
||||||
|
VPN_PASSWORD=vpnpassword
|
||||||
|
VPN_PUBLIC_IP=
|
||||||
|
VPN_L2TP_NET=
|
||||||
|
VPN_L2TP_LOCAL=
|
||||||
|
VPN_L2TP_REMOTE=
|
||||||
|
VPN_XAUTH_NET=
|
||||||
|
VPN_XAUTH_REMOTE=
|
||||||
|
VPN_DNS1=
|
||||||
|
VPN_DNS2=
|
264
docker/l2tp/l2tp.sh
Normal file
264
docker/l2tp/l2tp.sh
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||||
|
export PATH
|
||||||
|
#
|
||||||
|
# This is a Shell script for configure and start L2TP/IPSec VPN server with Docker image
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 Teddysun <i@teddysun.com>
|
||||||
|
#
|
||||||
|
# Reference URL:
|
||||||
|
# https://github.com/libreswan/libreswan
|
||||||
|
# https://github.com/xelerance/xl2tpd
|
||||||
|
|
||||||
|
if [ ! -f "/.dockerenv" ]; then
|
||||||
|
echo "Error: This script must be run in a Docker container." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ip link add dummy0 type dummy 2>&1 | grep -q "not permitted"; then
|
||||||
|
echo "Error: This Docker image must be run in privileged mode." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip link delete dummy0 >/dev/null 2>&1
|
||||||
|
|
||||||
|
rand(){
|
||||||
|
index=0
|
||||||
|
str=""
|
||||||
|
for i in {a..z}; do arr[index]=${i}; index=$(expr ${index} + 1); done
|
||||||
|
for i in {A..Z}; do arr[index]=${i}; index=$(expr ${index} + 1); done
|
||||||
|
for i in {0..9}; do arr[index]=${i}; index=$(expr ${index} + 1); done
|
||||||
|
for i in {1..10}; do str="$str${arr[$RANDOM%$index]}"; done
|
||||||
|
echo ${str}
|
||||||
|
}
|
||||||
|
|
||||||
|
is_64bit(){
|
||||||
|
if [ "$(getconf WORD_BIT)" == "32" ] && [ "$(getconf LONG_BIT)" == "64" ]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Environment file name
|
||||||
|
l2tp_env_file="/etc/l2tp.env"
|
||||||
|
# Auto generated
|
||||||
|
if [ -z "${VPN_IPSEC_PSK}" ] && [ -z "${VPN_USER}" ] && [ -z "${VPN_PASSWORD}" ]; then
|
||||||
|
if [ -f "${l2tp_env_file}" ]; then
|
||||||
|
echo "Loading previously generated environment variables for L2TP/IPSec VPN Server..."
|
||||||
|
. "${l2tp_env_file}"
|
||||||
|
else
|
||||||
|
echo "L2TP/IPSec VPN Server environment variables is not set. Use default environment variables..."
|
||||||
|
VPN_IPSEC_PSK="teddysun.com"
|
||||||
|
VPN_USER="vpnuser"
|
||||||
|
VPN_PASSWORD="$(rand)"
|
||||||
|
echo "VPN_IPSEC_PSK=${VPN_IPSEC_PSK}" > ${l2tp_env_file}
|
||||||
|
echo "VPN_USER=${VPN_USER}" >> ${l2tp_env_file}
|
||||||
|
echo "VPN_PASSWORD=${VPN_PASSWORD}" >> ${l2tp_env_file}
|
||||||
|
chmod 600 ${l2tp_env_file}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Environment variables:
|
||||||
|
# VPN_IPSEC_PSK
|
||||||
|
# VPN_USER
|
||||||
|
# VPN_PASSWORD
|
||||||
|
if [ -z "${VPN_IPSEC_PSK}" ] || [ -z "${VPN_USER}" ] || [ -z "${VPN_PASSWORD}" ]; then
|
||||||
|
echo "Error: Environment variables must be specified. please edit your environment file and retry again." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if printf '%s' "${VPN_IPSEC_PSK} ${VPN_USER} ${VPN_PASSWORD}" | LC_ALL=C grep -q '[^ -~]\+'; then
|
||||||
|
echo "Error: Environment variables must not contain non-ASCII characters." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${VPN_IPSEC_PSK} ${VPN_USER} ${VPN_PASSWORD}" in
|
||||||
|
*[\\\"\']*)
|
||||||
|
echo "Error: Environment variables must not contain these special characters like: \\ \" '"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Environment variables:
|
||||||
|
# VPN_PUBLIC_IP
|
||||||
|
PUBLIC_IP=${VPN_PUBLIC_IP:-''}
|
||||||
|
|
||||||
|
[ -z "${PUBLIC_IP}" ] && PUBLIC_IP=$( wget -qO- -t1 -T2 ipv4.icanhazip.com )
|
||||||
|
[ -z "${PUBLIC_IP}" ] && PUBLIC_IP=$( wget -qO- -t1 -T2 ipinfo.io/ip )
|
||||||
|
|
||||||
|
# Environment variables:
|
||||||
|
# VPN_L2TP_NET
|
||||||
|
# VPN_L2TP_LOCAL
|
||||||
|
# VPN_L2TP_REMOTE
|
||||||
|
# VPN_XAUTH_NET
|
||||||
|
# VPN_XAUTH_REMOTE
|
||||||
|
# VPN_DNS1
|
||||||
|
# VPN_DNS2
|
||||||
|
L2TP_NET=${VPN_L2TP_NET:-'192.168.18.0/24'}
|
||||||
|
L2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.18.1'}
|
||||||
|
L2TP_REMOTE=${VPN_L2TP_REMOTE:-'192.168.18.10-192.168.18.250'}
|
||||||
|
XAUTH_NET=${VPN_XAUTH_NET:-'192.168.20.0/24'}
|
||||||
|
XAUTH_REMOTE=${VPN_XAUTH_REMOTE:-'192.168.20.10-192.168.20.250'}
|
||||||
|
DNS1=${VPN_DNS1:-'8.8.8.8'}
|
||||||
|
DNS2=${VPN_DNS2:-'8.8.4.4'}
|
||||||
|
|
||||||
|
# Create IPSec config
|
||||||
|
cat > /etc/ipsec.conf <<EOF
|
||||||
|
version 2.0
|
||||||
|
|
||||||
|
config setup
|
||||||
|
protostack=netkey
|
||||||
|
nhelpers=0
|
||||||
|
uniqueids=no
|
||||||
|
interfaces=%defaultroute
|
||||||
|
virtual-private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!${L2TP_NET},%v4:!${XAUTH_NET}
|
||||||
|
|
||||||
|
conn shared
|
||||||
|
left=%defaultroute
|
||||||
|
leftid=${PUBLIC_IP}
|
||||||
|
right=%any
|
||||||
|
encapsulation=yes
|
||||||
|
authby=secret
|
||||||
|
pfs=no
|
||||||
|
rekey=no
|
||||||
|
keyingtries=5
|
||||||
|
dpddelay=30
|
||||||
|
dpdtimeout=120
|
||||||
|
dpdaction=clear
|
||||||
|
ike=3des-sha1,3des-sha2,aes-sha1,aes-sha1;modp1024,aes-sha2,aes-sha2;modp1024
|
||||||
|
phase2alg=3des-sha1,3des-sha2,aes-sha1,aes-sha2,aes256-sha2_512
|
||||||
|
sha2-truncbug=yes
|
||||||
|
|
||||||
|
conn l2tp-psk
|
||||||
|
auto=add
|
||||||
|
leftprotoport=17/1701
|
||||||
|
rightprotoport=17/%any
|
||||||
|
type=transport
|
||||||
|
phase2=esp
|
||||||
|
also=shared
|
||||||
|
|
||||||
|
conn xauth-psk
|
||||||
|
auto=add
|
||||||
|
leftsubnet=0.0.0.0/0
|
||||||
|
rightaddresspool=${XAUTH_REMOTE}
|
||||||
|
modecfgdns=${DNS1},${DNS2}
|
||||||
|
leftxauthserver=yes
|
||||||
|
rightxauthclient=yes
|
||||||
|
leftmodecfgserver=yes
|
||||||
|
rightmodecfgclient=yes
|
||||||
|
modecfgpull=yes
|
||||||
|
xauthby=file
|
||||||
|
ike-frag=yes
|
||||||
|
ikev2=never
|
||||||
|
cisco-unity=yes
|
||||||
|
also=shared
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/xl2tpd/xl2tpd.conf <<EOF
|
||||||
|
[global]
|
||||||
|
port = 1701
|
||||||
|
|
||||||
|
[lns default]
|
||||||
|
local ip = ${L2TP_LOCAL}
|
||||||
|
ip range = ${L2TP_REMOTE}
|
||||||
|
require chap = yes
|
||||||
|
refuse pap = yes
|
||||||
|
require authentication = yes
|
||||||
|
name = l2tpd
|
||||||
|
pppoptfile = /etc/ppp/options.xl2tpd
|
||||||
|
length bit = yes
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/ppp/options.xl2tpd <<EOF
|
||||||
|
+mschap-v2
|
||||||
|
ipcp-accept-local
|
||||||
|
ipcp-accept-remote
|
||||||
|
ms-dns ${DNS1}
|
||||||
|
ms-dns ${DNS2}
|
||||||
|
noccp
|
||||||
|
auth
|
||||||
|
mtu 1280
|
||||||
|
mru 1280
|
||||||
|
proxyarp
|
||||||
|
lcp-echo-failure 4
|
||||||
|
lcp-echo-interval 30
|
||||||
|
connect-delay 5000
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/ipsec.secrets <<EOF
|
||||||
|
%any %any : PSK "${VPN_IPSEC_PSK}"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/ppp/chap-secrets <<EOF
|
||||||
|
${VPN_USER} l2tpd ${VPN_PASSWORD} *
|
||||||
|
EOF
|
||||||
|
|
||||||
|
VPN_PASSWORD_ENC=$(openssl passwd -1 "${VPN_PASSWORD}")
|
||||||
|
cat > /etc/ipsec.d/passwd <<EOF
|
||||||
|
${VPN_USER}:${VPN_PASSWORD_ENC}:xauth-psk
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod 600 /etc/ipsec.secrets /etc/ppp/chap-secrets /etc/ipsec.d/passwd
|
||||||
|
|
||||||
|
# Update sysctl settings
|
||||||
|
if is_64bit; then
|
||||||
|
SHM_MAX=68719476736
|
||||||
|
SHM_ALL=4294967296
|
||||||
|
else
|
||||||
|
SHM_MAX=4294967295
|
||||||
|
SHM_ALL=268435456
|
||||||
|
fi
|
||||||
|
|
||||||
|
sysctl -eqw kernel.msgmnb=65536
|
||||||
|
sysctl -eqw kernel.msgmax=65536
|
||||||
|
sysctl -eqw kernel.shmmax=${SHM_MAX}
|
||||||
|
sysctl -eqw kernel.shmall=${SHM_ALL}
|
||||||
|
sysctl -eqw net.ipv4.ip_forward=1
|
||||||
|
sysctl -eqw net.ipv4.conf.all.accept_source_route=0
|
||||||
|
sysctl -eqw net.ipv4.conf.all.accept_redirects=0
|
||||||
|
sysctl -eqw net.ipv4.conf.all.send_redirects=0
|
||||||
|
sysctl -eqw net.ipv4.conf.all.rp_filter=0
|
||||||
|
sysctl -eqw net.ipv4.conf.default.accept_source_route=0
|
||||||
|
sysctl -eqw net.ipv4.conf.default.accept_redirects=0
|
||||||
|
sysctl -eqw net.ipv4.conf.default.send_redirects=0
|
||||||
|
sysctl -eqw net.ipv4.conf.default.rp_filter=0
|
||||||
|
sysctl -eqw net.ipv4.conf.eth0.send_redirects=0
|
||||||
|
sysctl -eqw net.ipv4.conf.eth0.rp_filter=0
|
||||||
|
|
||||||
|
# Create iptables rules
|
||||||
|
iptables -I INPUT 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP
|
||||||
|
iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP
|
||||||
|
iptables -I INPUT 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
iptables -I INPUT 4 -p udp -m multiport --dports 500,4500 -j ACCEPT
|
||||||
|
iptables -I INPUT 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT
|
||||||
|
iptables -I INPUT 6 -p udp --dport 1701 -j DROP
|
||||||
|
iptables -I FORWARD 1 -m conntrack --ctstate INVALID -j DROP
|
||||||
|
iptables -I FORWARD 2 -i eth+ -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
iptables -I FORWARD 3 -i ppp+ -o eth+ -j ACCEPT
|
||||||
|
iptables -I FORWARD 4 -i ppp+ -o ppp+ -s "${L2TP_NET}" -d "${L2TP_NET}" -j ACCEPT
|
||||||
|
iptables -I FORWARD 5 -i eth+ -d "${XAUTH_NET}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
iptables -I FORWARD 6 -s "${XAUTH_NET}" -o eth+ -j ACCEPT
|
||||||
|
iptables -A FORWARD -j DROP
|
||||||
|
iptables -t nat -I POSTROUTING -s "${XAUTH_NET}" -o eth+ -m policy --dir out --pol none -j MASQUERADE
|
||||||
|
iptables -t nat -I POSTROUTING -s "${L2TP_NET}" -o eth+ -j MASQUERADE
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
L2TP/IPsec VPN Server with the Username and Password is below:
|
||||||
|
|
||||||
|
Server IP: ${PUBLIC_IP}
|
||||||
|
IPSec PSK: ${VPN_IPSEC_PSK}
|
||||||
|
Username : ${VPN_USER}
|
||||||
|
Password : ${VPN_PASSWORD}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Load IPsec kernel module
|
||||||
|
modprobe af_key
|
||||||
|
|
||||||
|
# Start services
|
||||||
|
mkdir -p /run/pluto /var/run/pluto /var/run/xl2tpd
|
||||||
|
rm -f /run/pluto/pluto.pid /var/run/pluto/pluto.pid /var/run/xl2tpd.pid
|
||||||
|
/usr/sbin/ipsec start
|
||||||
|
exec /usr/sbin/xl2tpd -D -c /etc/xl2tpd/xl2tpd.conf
|
131
docker/l2tp/l2tpctl.sh
Normal file
131
docker/l2tp/l2tpctl.sh
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||||
|
export PATH
|
||||||
|
#
|
||||||
|
# This is a Shell script for configure and start L2TP/IPSec VPN server with Docker image
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 Teddysun <i@teddysun.com>
|
||||||
|
#
|
||||||
|
# Reference URL:
|
||||||
|
# https://github.com/libreswan/libreswan
|
||||||
|
# https://github.com/xelerance/xl2tpd
|
||||||
|
|
||||||
|
rand(){
|
||||||
|
index=0
|
||||||
|
str=""
|
||||||
|
for i in {a..z}; do arr[index]=${i}; index=$(expr ${index} + 1); done
|
||||||
|
for i in {A..Z}; do arr[index]=${i}; index=$(expr ${index} + 1); done
|
||||||
|
for i in {0..9}; do arr[index]=${i}; index=$(expr ${index} + 1); done
|
||||||
|
for i in {1..10}; do str="$str${arr[$RANDOM%$index]}"; done
|
||||||
|
echo ${str}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_users(){
|
||||||
|
if [ ! -f /etc/ppp/chap-secrets ];then
|
||||||
|
echo "Error: /etc/ppp/chap-secrets file not found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
local line="+-------------------------------------------+\n"
|
||||||
|
local string=%20s
|
||||||
|
printf "${line}|${string} |${string} |\n${line}" Username Password
|
||||||
|
grep -v "^#" /etc/ppp/chap-secrets | awk '{printf "|'${string}' |'${string}' |\n", $1,$3}'
|
||||||
|
printf ${line}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_user(){
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
read -p "Please enter Username:" user
|
||||||
|
if [ -z ${user} ]; then
|
||||||
|
echo "Username can not be empty"
|
||||||
|
else
|
||||||
|
grep -w "${user}" /etc/ppp/chap-secrets > /dev/null 2>&1
|
||||||
|
if [ $? -eq 0 ];then
|
||||||
|
echo "Username (${user}) already exists. Please re-enter your username."
|
||||||
|
else
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
pass="$(rand)"
|
||||||
|
echo "Please enter ${user}'s password:"
|
||||||
|
read -p "(Default Password: ${pass}):" tmppass
|
||||||
|
[ ! -z ${tmppass} ] && pass=${tmppass}
|
||||||
|
pass_enc=$(openssl passwd -1 "${pass}")
|
||||||
|
echo "${user} l2tpd ${pass} *" >> /etc/ppp/chap-secrets
|
||||||
|
echo "${user}:${pass_enc}:xauth-psk" >> /etc/ipsec.d/passwd
|
||||||
|
echo "Username (${user}) add completed."
|
||||||
|
}
|
||||||
|
|
||||||
|
del_user(){
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
read -p "Please enter Username you want to delete it:" user
|
||||||
|
if [ -z ${user} ]; then
|
||||||
|
echo "Username can not be empty"
|
||||||
|
else
|
||||||
|
grep -w "${user}" /etc/ppp/chap-secrets >/dev/null 2>&1
|
||||||
|
if [ $? -eq 0 ];then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo "Username (${user}) is not exists. Please re-enter your username."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets
|
||||||
|
sed -i "/^\<${user}\>/d" /etc/ipsec.d/passwd
|
||||||
|
echo "Username (${user}) delete completed."
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_user(){
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
read -p "Please enter Username you want to change password:" user
|
||||||
|
if [ -z ${user} ]; then
|
||||||
|
echo "Username can not be empty"
|
||||||
|
else
|
||||||
|
grep -w "${user}" /etc/ppp/chap-secrets >/dev/null 2>&1
|
||||||
|
if [ $? -eq 0 ];then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo "Username (${user}) is not exists. Please re-enter your username."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
pass="$(rand)"
|
||||||
|
echo "Please enter ${user}'s new password:"
|
||||||
|
read -p "(Default Password: ${pass}):" tmppass
|
||||||
|
[ ! -z ${tmppass} ] && pass=${tmppass}
|
||||||
|
pass_enc=$(openssl passwd -1 "${pass}")
|
||||||
|
sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets
|
||||||
|
sed -i "/^\<${user}\>/d" /etc/ipsec.d/passwd
|
||||||
|
echo "${user} l2tpd ${pass} *" >> /etc/ppp/chap-secrets
|
||||||
|
echo "${user}:${pass_enc}:xauth-psk" >> /etc/ipsec.d/passwd
|
||||||
|
echo "Username ${user}'s password has been changed."
|
||||||
|
}
|
||||||
|
|
||||||
|
action=$1
|
||||||
|
case ${action} in
|
||||||
|
-l|--list)
|
||||||
|
list_users
|
||||||
|
;;
|
||||||
|
-a|--add)
|
||||||
|
add_user
|
||||||
|
;;
|
||||||
|
-d|--del)
|
||||||
|
del_user
|
||||||
|
;;
|
||||||
|
-m|--mod)
|
||||||
|
mod_user
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
echo "Usage: `basename $0` -l,--list List all users"
|
||||||
|
echo " `basename $0` -a,--add Add a user"
|
||||||
|
echo " `basename $0` -d,--del Delete a user"
|
||||||
|
echo " `basename $0` -m,--mod Modify a user password"
|
||||||
|
echo " `basename $0` -h,--help Print this help information"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: `basename $0` [-l,--list|-a,--add|-d,--del|-m,--mod|-h,--help]" && exit
|
||||||
|
;;
|
||||||
|
esac
|
Loading…
x
Reference in New Issue
Block a user