本文目标
在 Ubuntu 上安装配置 strongSwan,使用 letsencrypt 的 SSL 证书,并采用 FreeRADIUS 作为用户认证审计等。
使用 ss-redir(包含在 shadowsocks-libev) 转发非 CN 的 IP 的请求到 ss-server(包含在)。
本文测试环境
本文假设 strongSwan 的 hostname 为 vpn.example.net,IP 地址为 1.2.3.4,FreeRADIUS 的 hostname 为 radius.example.net。
所以在下面的代码中如果看到这些假设的值,请自行修改为合适自己的值。
安装
$ apt install strongswan strongswan-plugin-eap-radius strongswan-plugin-xauth-eap
$ apt install letsencrypt
$ letsencrypt certonly --standalone -d vpn.example.net -m john.doe@example.net --agree-tos
$ cp /etc/letsencrypt/live/vpn.example.net/cert.pem /etc/ipsec.d/certs/
$ cp /etc/letsencrypt/live/vpn.example.net/privkey.pem /etc/ipsec.d/private/
$ cp /etc/letsencrypt/live/vpn.example.net/chain.pem /etc/ipsec.d/cacerts/
/etc/crontab 增加:
30 0 1 * * root letsencrypt renew --quiet
30 1 1 * * root /root/bin/renew-cert.sh
其中 /root/bin/renew-cert.sh (chmod +x) 内容如下:
#!/bin/sh
from="/etc/letsencrypt/live/vpn.example.net"
to="/etc/ipsec.d"
cp "${from}/chain.pem" "${to}/cacerts/chain.pem"
cp "${from}/cert.pem" "${to}/certs/cert.pem"
cp "${from}/privkey.pem" "${to}/private/privkey.pem"
配置文件
/etc/sysctl.conf
开启 IPv4 包转发:
...
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
...
/etc/ipsec.conf
# ipsec.conf - strongSwan IPsec configuration file
# basic configuration
config setup
# strictcrlpolicy=yes
uniqueids = no
conn %default
dpdaction=clear
forceencaps=yes
leftsubnet=0.0.0.0/0
right=%any
rightsourceip=192.168.100.2/24
rightdns=1.2.3.4
conn Cisco-IPSec
keyexchange=ikev1
auto=add
left=%defaultroute
leftauth=psk
rightauth=psk
rightauth2=xauth
conn IKEv2
keyexchange=ikev2
auto=add
fragmentation=yes
compress=yes
leftcert=cert.pem
leftsendcert=always
rightauth=eap-radius
eap_identity=%identity
# Windows and BlackBerry clients usually goes here
conn IKEv2-mschapv2
also=IKEv2
# Apple clients usually goes here
conn IKEv2-mschapv2-apple
also=IKEv2
leftid=vpn.example.net
说明:
/etc/ipsec.secrets
# This file holds shared secrets or RSA private keys for authentication.
# RSA private key for this host, authenticating it to any other host
# which knows the public part.
: RSA privkey.pem
: PSK "the Great Wall"
/etc/strongswan.d/charon/eap-radius.conf
eap-radius {
# Send RADIUS accounting information to RADIUS servers.
accounting = yes
# Close the IKE_SA if there is a timeout during interim RADIUS accounting
# updates.
# accounting_close_on_timeout = yes
# Interval in seconds for interim RADIUS accounting updates, if not
# specified by the RADIUS server in the Access-Accept message.
# accounting_interval = 0
# If enabled, accounting is disabled unless an IKE_SA has at least one
# virtual IP. Only for IKEv2, for IKEv1 a virtual IP is strictly necessary.
# accounting_requires_vip = no
# Use class attributes in Access-Accept messages as group membership
# information.
# class_group = no
# Closes all IKE_SAs if communication with the RADIUS server times out. If
# it is not set only the current IKE_SA is closed.
# close_all_on_timeout = no
# Send EAP-Start instead of EAP-Identity to start RADIUS conversation.
# eap_start = no
# Use filter_id attribute as group membership information.
# filter_id = no
# Prefix to EAP-Identity, some AAA servers use a IMSI prefix to select the
# EAP method.
# id_prefix =
# Whether to load the plugin. Can also be an integer to increase the
# priority of this plugin.
load = yes
# NAS-Identifier to include in RADIUS messages.
# nas_identifier = strongSwan
# Port of RADIUS server (authentication).
# port = 1812
# Base to use for calculating exponential back off.
# retransmit_base = 1.4
# Timeout in seconds before sending first retransmit.
# retransmit_timeout = 2.0
# Number of times to retransmit a packet before giving up.
# retransmit_tries = 4
# Shared secret between RADIUS and NAS. If set, make sure to adjust the
# permissions of the config file accordingly.
secret = yourPassword
# IP/Hostname of RADIUS server.
server = radius.example.net
# Number of sockets (ports) to use, increase for high load.
# sockets = 1
dae {
# Enables support for the Dynamic Authorization Extension (RFC 5176).
# enable = no
# Address to listen for DAE messages from the RADIUS server.
# listen = 0.0.0.0
# Port to listen for DAE requests.
# port = 3799
# Shared secret used to verify/sign DAE messages. If set, make sure to
# adjust the permissions of the config file accordingly.
# secret =
}
forward {
# RADIUS attributes to be forwarded from IKEv2 to RADIUS.
# ike_to_radius =
# Same as ike_to_radius but from RADIUS to IKEv2.
# radius_to_ike =
}
# Section to specify multiple RADIUS servers.
servers {
}
# Section to configure multiple XAuth authentication rounds via RADIUS.
xauth {
}
}
说明:
注意修改 secret 和 server 参数:
# Shared secret between RADIUS and NAS. If set, make sure to adjust the
# permissions of the config file accordingly.
secret = yourPassword
# IP/Hostname of RADIUS server.
server = radius.example.net
/etc/strongswan.d/charon/xauth-eap.conf
xauth-eap {
# EAP plugin to be used as backend for XAuth credential verification.
backend = radius
# Whether to load the plugin. Can also be an integer to increase the
# priority of this plugin.
load = yes
}
ss-redir
在 /etc/rc.local 的 exit 0 前添加如下代码,便于开机时自动建立监听于 8081 端口的转发,它将请求转发到 ss-server:
ss-redir -c /usr/local/etc/shadowsocks-libev/config.json -u -A -l 8081 -b 0.0.0.0 > /dev/null 2>&1 &
iptables
将下面的内容编写文件脚本文件 /root/bin/iptable.sh,需要 ipset (apt install ipset):
#!/bin/sh
# 转发客户端请求。注意网段和 ipsec.conf 里要一致。网卡使用外网网卡。
out_iface="eth1"
server_IP="1.2.3.4"
subnet="192.168.100.0/24"
# strongswan
iptables -A INPUT -p udp --dport 500 -j ACCEPT
iptables -A INPUT -p udp --dport 4500 -j ACCEPT
# Moved to /etc/sysctl.conf: net.ipv4.ip_forward=1
# 打开网卡转发功能。要把客户端的请求转发到公网网卡
# echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s ${subnet} -o ${out_iface} -j MASQUERADE
# 允许转发
iptables -A FORWARD -s ${subnet} -j ACCEPT
[ -r chnroute.txt ] || curl 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | grep ipv4 | grep CN | awk -F\| '{ printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > chnroute.txt
iptables -t nat -N SHADOWSOCKS
iptables -t nat -A SHADOWSOCKS -d $server_IP -j RETURN
# 内网网段
iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN
iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN
# 创建ipset列表
#ipset -exist create gfwlist hash:net
ipset -exist create chnroute hash:net
cat chnroute.txt | sudo xargs -I ip ipset -exist add chnroute ip
# gfwlist 走ss转发
#iptables -t nat -A SHADOWSOCKS -m set --match-set gfwlist dst -p tcp -j REDIRECT --to-ports 8081
# 国内ip表直连
iptables -t nat -A SHADOWSOCKS -m set --match-set chnroute dst -j RETURN
# 其他连接走ss转发
iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 8081
iptables -t nat -A PREROUTING -s ${subnet} -p tcp -j SHADOWSOCKS
# ss-redir
iptables -A INPUT -p tcp -s ${subnet}--dport 8081 -j ACCEPT
iptables -A INPUT -p tcp --dport 8081 -j DROP
注意这段代码只是示意,请根据实际情况改进,比如定期更新 ipset chnroute 的 IP 列表,使用 iptables-persistent(apt install iptables-persistent) 来持久化 iptables 规则等。
在使用 iptables-persistent 时可能会用到的命令:
$ iptables-save > /etc/iptables/rules.v4
$ ip6tables-save > /etc/iptables/rules.v6
测试
$ ipsec start --nofork
在 PostgreSQL 数据库 radius 中执行如下 SQL 语句:
/* 用户名为 yourVPNUsername 的密码为 yourVPNPassword */
insert into radcheck(username, attribute, op, value) values('yourVPNUsername', 'Password', '==', 'yourVPNPassword');
/* 可以用来配置月流量为 1GiB */
/* insert into radcheck(username, attribute, op, value) values('yourVPNUsername', 'Max-Monthly-Traffic', ':=', '1024'); */
/* 控制组 plan-monthly-1GiB 的用户的并发会话为 2 */
insert into radgroupcheck(groupname, attribute, op, value) values('plan-monthly-1GiB', 'Simultaneous-Use', ':=', '2');
/* 限制组 plan-monthly-1GiB 的用户的月流量为 1024 MiB */
insert into radgroupcheck(groupname, attribute, op, value) values('plan-monthly-1GiB', 'Max-Monthly-Traffic', ':=', '1024');
/* 将用户 yourVPNUsername 添加到组 plan-monthly-1GiB */
insert into radusergroup(username, groupname) values('yourVPNUsername', 'plan-monthly-1GiB');
注意这里用到的 Max-Monthly-Traffic 是在在 FreeBSD 上安装 FreeRADIUS中定义的。
在 VPN 客户端可以使用 IKEv2 或者 Cisco IPSec 来连接。
IKEv2:
Server Address(服务器地址): vpn.example.net
Remote ID(远程 ID): vpn.example.net
Authentication Settings(鉴定设置): Username(用户名)
Username(用户名): yourVPNUsername
Password(密码): yourVPNPassword
Cisco IPSec:
Server Address(服务器地址): vpn.example.net
Account Name(帐户名称): yourVPNUsername
Password(密码): yourVPNPassword
Authentication Settings(鉴定设置):
Machine Authentication(机器鉴定):
Shared Secret(共享的密钥): the Great Wall
(Shared Secret 是配置在 /etc/ipsec.secrets 中的 PSK)
启动
service strongswan start
#cisco-ipsec, #freeradius, #ikev2, #iptables-persistent, #letsencrypt, #postgresql, #shadowsocks-libev, #ss-redir, #strongswan, #ubuntu
#ipset, #iptables