github twitter email rss
Raspberry Pi 搭建Anyconnect VPN
Sep 29, 2015
4 minutes read
  • Debian >=7, ubuntu >=14.04 的可以直接使用这个脚本一键安装

https://github.com/fanyueciyuan/eazy-for-ss/tree/master/ocservauto

  • Raspberry Pi 比较特殊点有些地方需要改进,我们改为手工编译,原始脚本的链接是在

https://github.com/humiaozuzu/ocserv-build/blob/master/build-src.sh

稍加修改,使用最新版本的ocserv-0.10.8,编译liblz4,开启Compression(lz4)

#!/bin/bash

apt-get install -y build-essential autogen pkg-config texinfo libhogweed2 libgmp3-dev gettext
apt-get install -y libxml2-dev libgeos++-dev libpq-dev libbz2-dev libreadline-dev libtool automake
apt-get install -y unbound-anchor
mkdir /etc/unbound
unbound-anchor -a "/etc/unbound/root.key"

mkdir -p /opt/src

cd /opt/src
wget http://www.lysator.liu.se/~nisse/archive/nettle-2.7.tar.gz
wget ftp://ftp.gnu.org/gnu/nettle/nettle-3.2.tar.gz
tar xvzf nettle-3.2.tar.gz
cd /opt/src/nettle-3.2
./configure --enable-shared --prefix=/opt/local --disable-assembler
make
make install

cd /opt/src
wget http://ftp.gnu.org/gnu/libtasn1/libtasn1-4.8.tar.gz
tar xvzf libtasn1-4.8.tar.gz
cd /opt/src/libtasn1-4.8
./configure --prefix=/opt/local
make
make install

cd /opt/src
wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz
tar xvzf libffi-3.2.1.tar.gz
cd /opt/src/libffi-3.2.1
./configure --prefix=/opt/local
make
make install

cd /opt/src
wget https://p11-glue.freedesktop.org/releases/p11-kit-0.23.2.tar.gz
tar xvzf p11-kit-0.23.2.tar.gz
cd /opt/src/p11-kit-0.23.2
PKG_CONFIG_PATH=/opt/local/lib/pkgconfig ./configure --prefix=/opt/local
make
make install

cd /opt/src
wget ftp://ftp.gnutls.org/gcrypt/gnutls/v3.4/gnutls-3.4.9.tar.xz
tar xvfJ gnutls-3.4.9.tar.xz
cd /opt/src/gnutls-3.4.9
PKG_CONFIG_PATH=/opt/local/lib/pkgconfig ./configure --enable-shared --prefix=/opt/local
make
make install

cd /opt/src
mkdir lz4
LZ4_VERSION=`curl -s "https://github.com/Cyan4973/lz4/releases/latest" | sed -n 's/^.*tag\/\(.*\)".*/\1/p'` 
curl -SL "https://github.com/Cyan4973/lz4/archive/$LZ4_VERSION.tar.gz" -o lz4.tar.gz
tar -xf lz4.tar.gz -C lz4 --strip-components=1 
cd lz4 
make -j"$(nproc)" && make install
cd ..
ln -sf /usr/local/lib/liblz4.* /usr/lib/

cd /opt/src
wget https://www.openssl.org/source/openssl-1.0.1s.tar.gz
tar xvzf openssl-1.0.1s.tar.gz
cd /opt/src/openssl-1.0.1s
./config
make depend
make
make install

cd /opt/src
wget https://github.com/netcookies/ocserv-backup/raw/master/ocserv-0.10.8.tar.xz
tar xvf ocserv-0.10.8.tar.xz
cd /opt/src/ocserv-0.10.8
PKG_CONFIG_PATH=/opt/local/lib/pkgconfig ./configure --prefix=/opt/ocserv
LD_LIBRARY_PATH=/opt/local/lib make
make install
  • 编译安装成功后,运行以下命令测试下是否安装成功

LD_LIBRARY_PATH=/opt/local/lib /opt/ocserv/sbin/ocserv --help


  • 附上一些配置文件:

/opt/ocserv/etc/config

#auth = "certificate"
auth = "plain[passwd=/opt/ocserv/etc/ocpasswd]"
enable-auth = certificate
max-clients = 1024
max-same-clients = 0
tcp-port = 4443
udp-port = 4443
keepalive = 32400
dpd = 120
mobile-dpd = 1800
try-mtu-discovery = true
compression = true
server-cert = /opt/ocserv/ca/server-cert.pem
server-key = /opt/ocserv/ca/server-key.pem
ca-cert = /opt/ocserv/ca/ca-cert.pem
cert-user-oid = 2.5.4.3
#listen-host-is-dydns = true

tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-VERS-SSL3.0"
auth-timeout = 40
min-reauth-time = 120
cookie-timeout = 300
deny-roaming = false
rekey-time = 172800
rekey-method = ssl
use-utmp = true
use-occtl = true
pid-file = /var/run/ocserv.pid
socket-file = /var/run/ocserv-socket
run-as-user = nobody
run-as-group = daemon
device = vpns
output-buffer = 23000
# default-domain = example.com
ipv4-network = 10.0.2.0
ipv4-netmask = 255.255.255.0
dns = 8.8.8.8
dns = 8.8.4.4
ping-leases = false
cisco-client-compat = true

route = 10.20.30.0/255.255.255.0 #vpn服务器端内网的网段
no-route = 0.0.0.0/0.0.0.0 #默认其它流量不指向vpn,只当访问对端内网时指向vpn

no-route和router按实际需求添加

/opt/ocserv/etc/ocserv-up.sh

#!/bin/bash

#vars
OCSERV_CONFIG="/opt/ocserv/etc/config"

# turn on IP forwarding
#sysctl -w net.ipv6.conf.all.forwarding=1 > /dev/null 2>&1
sysctl -w net.ipv4.ip_forward=1 > /dev/null 2>&1

#get gateway and profiles
gw_intf_oc=`ip route show 0/0 | sort -k 7 | head -n 1 | sed -n 's/^default.* dev \([^ ]*\).*/\1/p'`
ocserv_tcpport=`sed -n 's/^tcp-.*=[ \t]*//p' $OCSERV_CONFIG`
ocserv_udpport=`sed -n 's/^udp-.*=[ \t]*//p' $OCSERV_CONFIG`
ocserv_ip4_work_mask=`sed -n 's/^ipv4-.*=[ \t]*//p' $OCSERV_CONFIG|sed 'N;s|\n|/|g'`

# turn on NAT over default gateway and VPN
if !(iptables-save -t nat | grep -q "$gw_intf_oc (ocserv)"); then
iptables -t nat -A POSTROUTING -s $ocserv_ip4_work_mask ! -d $ocserv_ip4_work_mask -m comment --comment "$gw_intf_oc (ocserv)" -j MASQUERADE
fi

if !(iptables-save -t filter | grep -q "$gw_intf_oc (ocserv2)"); then
iptables -A FORWARD -d $ocserv_ip4_work_mask -m comment --comment "$gw_intf_oc (ocserv2)" -j ACCEPT
fi

if !(iptables-save -t filter | grep -q "$gw_intf_oc (ocserv3)"); then
iptables -A INPUT -p tcp --dport $ocserv_tcpport -m comment --comment "$gw_intf_oc (ocserv3)" -j ACCEPT
fi

if [ "$ocserv_udpport" != "" ]; then
    if !(iptables-save -t filter | grep -q "$gw_intf_oc (ocserv4)"); then
        iptables -A INPUT -p udp --dport $ocserv_udpport -m comment --comment "$gw_intf_oc (ocserv4)" -j ACCEPT
    fi
fi

if !(iptables-save -t filter | grep -q "$gw_intf_oc (ocserv5)"); then
iptables -A FORWARD  -s $ocserv_ip4_work_mask -m state --state RELATED,ESTABLISHED -m comment --comment "$gw_intf_oc (ocserv5)" -j ACCEPT
fi

# turn on MSS fix
# MSS = MTU - TCP header - IP header
if !(iptables-save -t mangle | grep -q "$gw_intf_oc (ocserv6)"); then
iptables -t mangle -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -m comment --comment "$gw_intf_oc (ocserv6)" -j TCPMSS --clamp-mss-to-pmtu
fi

/opt/ocserv/etc/ocserv-down.sh

#!/bin/bash

# uncomment if you want to turn off IP forwarding
# sysctl -w net.ipv4.ip_forward=0

#del iptables

iptables-save | grep 'ocserv' | sed 's/^-A P/iptables -t nat -D P/' | sed 's/^-A FORWARD -p/iptables -t mangle -D FORWARD -p/' | sed 's/^-A/iptables -D/' | bash

/etc/init.d/ocserv

#!/bin/sh
### BEGIN INIT INFO
# Provides:          ocserv
# Required-Start:    $network $remote_fs $syslog
# Required-Stop:     $network $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: ocserv
# Description:       OpenConnect VPN server compatible with
#                    Cisco AnyConnect VPN.
### END INIT INFO

# Author: liyangyijie <liyangyijie@gmail.com>

# PATH should only include /usr/ if it runs after the mountnfs.sh script
PATH=/opt/ocserv/sbin:/opt/ocserv/bin:/sbin:/usr/sbin:/bin:/usr/bin
DESC=ocserv
NAME=ocserv
DAEMON=/opt/ocserv/sbin/ocserv
DAEMON_ARGS=""
CONFFILE="/opt/ocserv/etc/config"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
SERVER_UP="/opt/ocserv/etc/ocserv-up.sh"
SERVER_DOWN="/opt/ocserv/etc/ocserv-down.sh"

# Exit if the package is not installed
[ -x $DAEMON ] || exit 0

: ${USER:="root"}
: ${GROUP:="root"}

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

# Show details
VERBOSE="yes"

#
# Function that starts the daemon/service
#
do_start()
{
    # Add server up script
    [ -x ${SERVER_UP} ] && . ${SERVER_UP}

    # Take care of pidfile permissions
    mkdir /var/run/$NAME 2>/dev/null || true
    chown "$USER:$GROUP" /var/run/$NAME
    export LD_LIBRARY_PATH=/opt/local/lib
    
    # Return
    #   0 if daemon has been started
    #   1 if daemon was already running
    #   2 if daemon could not be started
    start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$GROUP --exec $DAEMON --test > /dev/null \
        || return 1
    start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$GROUP --exec $DAEMON -- \
        -c "$CONFFILE" $DAEMON_ARGS \
        || return 2
}

#
# Function that stops the daemon/service
#
do_stop()
{
    # Add server down script
    [ -x ${SERVER_DOWN} ] && . ${SERVER_DOWN}

    # Return
    #   0 if daemon has been stopped
    #   1 if daemon was already stopped
    #   2 if daemon could not be stopped
    #   other if a failure occurred
    start-stop-daemon --stop --quiet --retry=KILL/5 --pidfile $PIDFILE --exec $DAEMON
    RETVAL="$?"
    [ "$RETVAL" = 2 ] && return 2
    # Wait for children to finish too if this is a daemon that forks
    # and if the daemon is only ever run from this initscript.
    # If the above conditions are not satisfied then add some other code
    # that waits for the process to drop all resources that could be
    # needed by services started subsequently.  A last resort is to
    # sleep for some time.
    start-stop-daemon --stop --quiet --oknodo --retry=KILL/5 --exec $DAEMON
    [ "$?" = 2 ] && return 2
    # Many daemons don't delete their pidfiles when they exit.
    rm -f $PIDFILE
    return "$RETVAL"
}


case "$1" in
    start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
        do_start
        case "$?" in
            0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
            2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
    ;;
    stop)
    [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
    do_stop
    case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
    debug)
        DAEMON_ARGS="-f -d 2"
        [ "$2" != "" ] && DAEMON_ARGS="-f -d $2"
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
        do_start
        case "$?" in
            0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
            2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
    ;;
    status)
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
    ;;
    restart|force-reload)
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case "$?" in
            0|1)
                do_start
                case "$?" in
                    0) log_end_msg 0 ;;
                    1) log_end_msg 1 ;; # Old process is still running
                    *) log_end_msg 1 ;; # Failed to start
                esac
            ;;
            *)
            # Failed to stop
            log_end_msg 1
            ;;
        esac
    ;;
    *)
    echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload|debug}" >&2
    exit 3
    ;;
esac

  • 开机启动服务
chmod +x /etc/init.d/ocserv
update-rc.d ocserv defaults 99
  • 如果要使用证书认证,可以使用以下脚本一键生成,将生成的p12后缀文件在客户端导入即可
#!/bin/bash

AUTHOR="Maple"
VPN="Cisco SG for Maple"
DOMAIN="miao.hu"
CLIENT="user"

cd /opt/ocserv
mkdir ca
cd ca

cat << EOF > ca.tmpl
cn = "$VPN"
organization = "$AUTHOR"
serial = 1
expiration_days = 1000
ca
signing_key
cert_signing_key
crl_signing_key
EOF

cat << EOF > server.tmpl
cn = "$DOMAIN"
organization = "$AUTHOR"
serial = 2
expiration_days = 1000
signing_key
encryption_key
tls_www_server
EOF

certtool --generate-privkey --outfile ca-key.pem
certtool --generate-self-signed --load-privkey ca-key.pem --template ca.tmpl --outfile ca-cert.pem
certtool --generate-privkey --outfile server-key.pem
certtool --generate-certificate --load-privkey server-key.pem \
--load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem \
--template server.tmpl --outfile server-cert.pem

cat << EOF > user.tmpl
cn = "$CLIENT"
serial = 1824
expiration_days = 1000
signing_key
tls_www_client
EOF

certtool --generate-privkey --outfile user-key.pem
certtool --generate-certificate --load-privkey user-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template user.tmpl --outfile user-cert.pem
openssl pkcs12 -export -clcerts -in user-cert.pem -inkey user-key.pem -out user.p12

  • 其它问题: 如果ocserv所安装的服务器采用wlan0连接外网的话,可能会出现一启用vpn网络就断开的情况,则需要编辑/etc/defaults/ifplugd
...
INTERFACES="auto"
HOTPLUG_INTERFACES="eth0 wlan0"

参考: fanyueciyuan/eazy-for-ss humiaozuzu/ocserv-build http://www.boxtricks.com/raspberry-pi-drops-wireless-connect-after-openvpn-is-started/ http://superuser.com/questions/513351/debian-eth0-to-wlan0-forwarding-with-openvpn


Back to posts


comments powered by Disqus