使用 dnsmasq 和 shadowsocks-libev 构建一个干净的域名服务器

需要两台服务器。

一台位于离我们近的机房,这个机房可以是位于有域名服务器缓存污染的防火墙内。(当然如果不是有污染的环境,也没有必要写这篇文章。)

一台位于没有域名服务器缓存污染的防火墙外。

我们把这两台服务器分别取名为 ns.example.net 和 ss-server.example.net。

不能直接使用防火墙外的域名服务器作为客户端的域名服务器,是因为当域名解析数据包经过防火墙时会被投毒。

使用 dnsmasq 来分流不同的域名解析请求,是因为如果全部定向到防火墙外的域名服务器,对某些使用 CDN 的网站,特别是防火墙内的网站将会被解析得到距离我们较远的服务器的 IP。

在 ns.example.net 上安装和运行 dnsmasq 和 ss-tunnel(包含在 shadowsocks-libev),在 ss-server.example.net 上安装和运行 ss-server(包含在 shadowsocks-libev)。

部署图如下:

版本信息

本文测试环境:

  • Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-72-generic x86_64)
  • shadowsocks-libev 2.6.3

ss-server.example.net 的安装

见:安装 shadowsocks-libev 服务器端

ns.example.net 的安装

dnsmasq

轻量级 DNS 转发器、DHCP 和 TFTP 服务器。我们利用它的 DNS 转发功能。

安装

apt install dnsmasq

配置

确保文件 /etc/dnsmasq.conf 包含了如下代码,它通常位于最后一行:

# Include all files in a directory which end in .conf
conf-dir=/etc/dnsmasq.d/,*.conf

gfwlist2dnsmasq.sh

创建一个脚本文件 /usr/local/bin/gfwlist2dnsmasq.sh (chmod +x),内容如下:

#!/bin/sh
dnsmasqconf="/etc/dnsmasq.d/gfwlist.conf"
tmpconf="/tmp/gfwlist.conf.`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`"
curl -s -o /tmp/gfwlist.txt \
	https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt \
	&& base64 -d /tmp/gfwlist.txt \
	| awk -f $(cd "$(dirname "$0")"; pwd)/gfwlist2domainlist.awk \
		- /usr/local/etc/user_rule.txt \
	| grep -F -v -f "/usr/local/etc/skip_domain.txt" \
	| awk -f $(cd "$(dirname "$0")"; pwd)/domainlist2dnsmasq.awk \
		-v "noipset=noipset" \
		- \
	> "${tmpconf}" 2>/dev/null

diff -I '^#.*' "${dnsmasqconf}" "${tmpconf}" || \
	(cp "${tmpconf}" "${dnsmasqconf}" && service dnsmasq restart)

rm "${tmpconf}"

该脚本会生成 dnsmasq 配置文件 /etc/dnsmasq.d/gfwlist.conf 让 dnsmasq 将 gfwlist 中的域名的解析转发到 127.0.0.1:5353 端口。

gfwlist2domainlist.awk 和 domainlist2dnsmasq.awk 可以从 gfwlist2dnsmasq.awk 获得。

/usr/local/etc/user_rule.txt 可以用来存放额外的想交由 127.0.0.1:5353 端口解析的域名列表,
/usr/local/etc/skip_domain.txt 可以用来存放在 gfwlist 列表中,但是不想交由 127.0.0.1:5353 端口解析的域名。

在 /etc/rc.local 的 exit 0 之前添加,使其在开机时运行一次:

/usr/local/bin/gfwlist2dnsmasq.sh

由于 gfwlist 是不断更新的,所以可以在 /etc/crontab 中添加,以便每天早上4点20分更新一次:

20 4	* * *	root	/usr/local/bin/gfwlist2dnsmasq.sh

ss-tunnel

安装

同:安装 shadowsocks-libev 服务器端

启动

在 /etc/rc.local 的 exit 0 之前添加如下代码,以便开机时自动运行一个监听在 127.0.0.1:5353 端口,请求会通过隧道转到 8.8.8.8:53 上。

/usr/local/bin/ss-tunnel -c /usr/local/etc/shadowsocks-libev/config.json -l 5353 -L 8.8.8.8:53 -u > /dev/null 2>&1 &

测试

在 ns.example.net 上可以通过如下命令来测试 ss-tunnel 创建的隧道是否正常工作:

root@ns:~# nslookup 
> server 127.0.0.1
Default server: 127.0.0.1
Address: 127.0.0.1#53
> set port=5353
> www.google.com
Server:		127.0.0.1
Address:	127.0.0.1#5353

Non-authoritative answer:
Name:	www.google.com
Address: 172.217.25.4
> exit

#dnsmasq, #gfwlist, #gfwlist2dnsmasq-awk, #shadowsocks-libev, #ss-server, #ss-tunnel, #ubuntu

Advertisements

在 Mac OS X 上给 Telegram 单独设置代理服务器

由于众所周知的原因,并不是在世界上每一个国家都能顺利地使用 Telegram,那么我们不得不通过给 Telegram 设置代理服务器等途径来收发消息。

在 Mac OS X 的系统设置里可以设置 SOCKS Proxy,但是这样的缺点是所有其它应用程序也会被应用该代理设置。

本文将介绍如何使用 dsocks 软件来给 Telegram 应用程序单独设置代理服务器。

在开始本文前,你需要有一个 SOCKS 代理服务器,至于如何获得或者架设 SOCKS 代理服务器,并不是本文所要涵盖的内容。

安装 dsocks

使用 MacPorts 或者其它包管理工具都可以安装 dsocks。

$ port search dsocks
dsocks @1.6 (net)
SOCKS client wrapper for *BSD / Mac OS X

$ sudo port install dsocks

编写启动脚本

假设你的 SOCKS 代理服务器运行在 127.0.0.1 的 1080 端口,那么将下面这段脚本存储为文件 ~/bin/telegram.shchmod +x ~/bin/telegram.sh

#!/bin/sh
env DSOCKS_PROXY="127.0.0.1:1080" dsocks.sh \
	/Applications/Telegram.app/Contents/MacOS/Telegram \
	>/dev/null 2>&1 &

注意上述脚本中的 dsocks.sh,对于使用 MacPorts 来安装 dsocks 的情况下,它实际位于:

$ which dsocks.sh
/opt/local/bin/dsocks.sh

启动 Telegram

要启动 Telegram,则改为使用上述脚本来启动: ~/bin/telegram.sh

顺便说一下,给 Telegram 应用程序设置 HTTP/HTTPS 代理也能收发消息,但是延迟非常严重。

#dsocks, #mac-os-x, #macports, #socks-proxy, #telegram

Dream

I believe that every dream has its own nightmare, just like sun creates its own shadow.

And I believe that the biggest your dream is and hide your hope, the more severely you may fall.

It’s good to have a dream, but in order to pursue this dream to achieve what we deserve, we will hurt and be hurt, damage and be damaged.

At last, the dreamer would ask himself, that if he is willing to take this chance, that if he is willing to make this sacrifice?

So, the most important thing is not to have a dream, but to have the guts to face the nightmare, that is created by the dream.

He who fights with monsters might take care of lest he thereby become a monster.

And, when you gaze long into an abyss, the abyss also gaze into you.

Until then, do you still have the guts to gaze back into it, or even jump get through, jump into it?

strongSwan 的安装和配置

本文目标

在 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

在 FreeBSD 上安装 FreeRADIUS

本文目标

在 FreeBSD 上安装 FreeRADIUS 并使用 PostgreSQL 作为后端存储,并做一些常用的修改以便给 strongSwan 使用。

本文测试环境

  • FreeBSD 11.0-RELEASE-p8
  • FreeRADIUS 2.2.9

安装

$ cd /usr/ports/net/freeradius2 && make config

将 PGSQL(PostgreSQL database support)打勾。

$ make install clean

修改配置文件

/usr/local/etc/raddb/clients.conf

在最后添加,以便允许 strongSwan 访问该 FreeRADIUS:

# strongswan
client vpn.example.net {
        ipaddr = 1.2.3.4
        secret = mySecret
}

/usr/local/etc/raddb/dictionary

在最后添加:

ATTRIBUTE       Max-Monthly-Traffic     3003    integer
ATTRIBUTE       Monthly-Traffic-Limit   3004    integer

/usr/local/etc/raddb/eap.conf

修改 eap 节点下来的 default_eap_type,从 md5 修改为 mschapv2:

default_eap_type = mschapv2

/usr/local/etc/raddb/radiusd.conf

把 $INCLUDE sql.conf 前的注释去掉:

        #  Include another file that has the SQL-related configuration.
        #  This is another file only because it tends to be big.
        #
        $INCLUDE sql.conf

把 $INCLUDE sql/postgresql/counter.conf 前的注释去掉:

        #
        #  This module is an SQL enabled version of the counter module.
        #
        #  Rather than maintaining seperate (GDBM) databases of
        #  accounting info for each counter, this module uses the data
        #  stored in the raddacct table by the sql modules. This
        #  module NEVER does any database INSERTs or UPDATEs.  It is
        #  totally dependent on the SQL module to process Accounting
        #  packets.
        #
        $INCLUDE sql/postgresql/counter.conf

/usr/local/etc/raddb/sites-available/default

启用基于 SQL 数据库的授权和审计,即将节点 authorize、accounting、session、post-auth 中的 sql 前的注释去掉,并注释掉 session 节点中的 radutmp:

authorize {
...
        #
        #  Look in an SQL database.  The schema of the database
        #  is meant to mirror the "users" file.
        #
        #  See "Authorization Queries" in sql.conf
        sql
...
}
...
accounting {
...
        #
        #  Log traffic to an SQL database.
        #
        #  See "Accounting queries" in sql.conf
        sql
...
}
...
#  Session database, used for checking Simultaneous-Use. Either the radutmp
#  or rlm_sql module can handle this.
#  The rlm_sql module is *much* faster
session {
#       radutmp

        #
        #  See "Simultaneous Use Checking Queries" in sql.conf
        sql
}
...
post-auth {
...
        #
        #  After authenticating the user, do another SQL query.
        #
        #  See "Authentication Logging Queries" in sql.conf
        sql
...
        Post-Auth-Type REJECT {
                # log failed authentications in SQL, too.
                sql

...
        }
...
}

在节点 authorize 中最后增加:

authorize {
...
        monthlytrafficcounter
}

/usr/local/etc/raddb/sql/postgresql/counter.conf

在最后添加:

sqlcounter monthlytrafficcounter {
        counter-name = Monthly-Traffic
        check-name = Max-Monthly-Traffic
        reply-name = Monthly-Traffic-Limit
        sqlmod-inst = sql
        key = User-Name
        reset = monthly
        # 1048576 bytes = 1MiB
        query = "SELECT SUM(acctinputoctets + acctoutputoctets)/1048576 \
                FROM radacct \
                WHERE UserName='%{%k}' AND \
                AcctStartTime::ABSTIME::INT4 + AcctSessionTime > '%b'"
}

/usr/local/etc/raddb/sql/postgresql/dialup.conf

讲这两行前的注释去掉,以便启用并发会话个数检查:

# Uncomment simul_count_query to enable simultaneous use checking
simul_count_query = "SELECT COUNT(*) FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
simul_verify_query = "SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, FramedProtocol FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctSt
opTime IS NULL"

/usr/local/etc/raddb/sql.conf

将数据库从 mysql 修改为 postgresql,并配置数据库服务器登录信息:

sql {
        #
        #  Set the database to one of:
        #
        #       mysql, mssql, oracle, postgresql
        #
        database = "postgresql"
...
        # Connection info:
        server = "pgsql.example.net"
...
        login = "radius"
        password = "yourPassword"

        # Database table configuration for everything except Oracle
        radius_db = "radius"
...
        # Set to 'yes' to read radius clients from the database ('nas' table)
        # Clients will ONLY be read on server startup.  For performance
        # and security reasons, finding clients via SQL queries CANNOT
        # be done "live" while the server is running.
        # 
        readclients = yes
...
}

数据库的初始化

上面用到了 PostgreSQL 数据库服务器 pgsql.example.net 上的 radius 数据库,我们需要相应地初始化该数据库。
关于 PostgreSQL 数据库服务器的安装可以参考:在 FreeBSD 上安装 PostgreSQL

下面的命令示意了数据库用户 radius 和数据库 radius 的创建,以及表结构的初始化。
表结构相关的 SQL 语句可以在 FreeRADIUS 的配置文件目录中找到,位于 /usr/local/etc/raddb/sql/postgresql/schema.sql。

$ su - postgres
$ createuser -D -l -P -R -S radius
$ createdb -O radius radius
$ exit
$ psql -U radius -d radius < /usr/local/etc/raddb/sql/postgresql/schema.sql

设置为开机时自动启动

$ /usr/local/etc/rc.d/radiusd rcvar | sed s/NO/YES/ >> /etc/rc.conf

如果需要手动启动、重启或者查看运行状态可以分别使用如下命令:

$ /usr/local/etc/rc.d/radiusd start
$ /usr/local/etc/rc.d/radiusd restart
$ /usr/local/etc/rc.d/radiusd status

诊断

日志文件位于: /var/log/radius.log

#freebsd, #freeradius, #postgresql

在 FreeBSD 上安装 PostgreSQL

本文测试环境

  • FreeBSD 11.0-RELEASE-p8
  • postgresql96-server-9.6.2

安装

$ pkg install postgresql96-server-9.6.2

设置为开机时自动启动

$ /usr/local/etc/rc.d/postgresql rcvar | sed s/NO/YES/ >> /etc/rc.conf

初始化数据库

$ /usr/local/etc/rc.d/postgresql initdb

手动启动 PostgreSQL

$ /usr/local/etc/rc.d/postgresql start

Jail

如果你将 PostgreSQL 安装在 jail 内,可能会遇到如下错误:

running bootstrap script ... FATAL:  could not create shared memory segment: Function not implemented
DETAIL:  Failed system call was shmget(key=1, size=48, 03600).
child process exited with exit code 1

那么需要设置允许 sysvipc。

如果你使用的是 ezjail,那么可以修改 /usr/local/etc/ezjail/pgsql2_oxerr_net(假设 jailname 为 pgsql.example.net):

$ vi /usr/local/etc/ezjail/pgsql_example_net

修改如下参数增加“allow.sysvipc=1”:

export jail_pgsql_example_net_parameters="allow.sysvipc=1"

常用命令

列出所有可用数据库:

$ psql -U postgres -l

创建用户和数据库:

$ su - postgres
$ createuser -D -l -P -R -S example
$ createdb -O example example

以用户 example 登录数据库 example:

$ psql -U example -d example
example=> \?
example=> \d
example=> \q

允许用户从其它机器访问数据库:

$ vi /var/db/postgres/data96/pg_hba.conf

在最后添加类似如下代码,比如这里是允许用户 example 可以从 IP 为 192.168.0.100 的机器使用密码访问数据库 example:

host example example 192.168.0.100/32 password

#ezjail, #freebsd, #jail, #postgresql

安装 shadowsocks-libev 服务器端

版本信息

本文测试环境:

  • Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-72-generic x86_64)
  • shadowsocks-libev 2.6.3

安装 shadowsocks-libev 并设置 ss-server 开机自动启动

取出 shadowsocks-libev 源码,并切换到到 v2.6.3 分支:

$ git clone https://github.com/shadowsocks/shadowsocks-libev.git
$ cd shadowsocks-libev
$ git checkout v2.6.3
$ git submodule update --init --recursive

安装依赖:

$ sudo apt install autoconf automake libtool pkg-config libmbedtls-dev libsodium-dev libpcre3-dev libev-dev libudns-dev asciidoc xmlto make

编译并安装:

$ ./autogen.sh && ./configure && make
$ sudo make install

添加配置文件 /usr/local/etc/shadowsocks-libev/config.json:

{
    "server":"a.b.c.d",
    "server_port":8388,
    "local_port":1080,
    "password":"barfoo!",
    "timeout":60,
    "method":"aes-256-cfb"
}

注意修改 “server”:”a.b.c.d” 中的 a.b.c.d. 为你的服务器的外部 IP 地址,修改 password 和 method,其它参数按照需要修改。

设置开机时自动启动 ss-server,在 /etc/rc.local 的 exit 0 之前添加如下代码:

/usr/local/bin/ss-server -u -A -c /usr/local/etc/shadowsocks-libev/config.json > /dev/null 2>&1

配置 iptables 保护服务器 (可选)

由于实际使用中,shadowsocks-libev 客户端的 IP 地址可能是动态变化的,比如某次 PPPoE 拨号后 IP 地址可能就发生了变化。因此我们使用了 DDNS 来跟踪客户端 IP 地址,客户端通过 DDNS 来主动向 name server 上报 IP 地址,shadowsocks-libev 服务器需要在客户端 IP 地址发生变化后及时地修改 iptables 防火墙规则。

下面的防火墙规则中使用了 ipset (可以通过命令 apt install ipset 来安装)来存储客户端的 IP。

添加文件 /usr/local/bin/iptables.sh(注意 chmod +x):

#!/bin/sh
iptables -F

ext_ip="a.b.c.d"

ipset -exist create clients hash:net

# ping: allow ping from IPs in clients only
iptables -A INPUT -p icmp --icmp-type 8 -m set --match-set clients src -d ${ext_ip} -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type 0 -s ${ext_ip} -d 0/0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p icmp -j DROP
iptables -A OUTPUT -p icmp -j DROP

# ss-server: allow from IPs in clients only
iptables -A INPUT -p tcp -m set --match-set clients src --dport 8388 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp -m set --match-set clients dst --sport 8388 -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp --dport 8388 -j DROP
iptables -A OUTPUT -p tcp --sport 8388 -j DROP

注意修改 ext_ip=”a.b.c.d” 中的 a.b.c.d 修改为你的服务器的外部 IP 地址。
如果你有其它 iptables 规则请自行解决。

添加文件 /usr/local/bin/update-clients-ip.sh(注意 chmod +x),这段脚本通过向 name server 查询文件 /usr/local/etc/clients.txt 中的域名列表的 IP,在 IP 发生变化时更新 ipset:

#!/bin/sh
PATH=$PATH:/bin:/usr/bin

for domain in $(cat "/usr/local/etc/clients.txt"); do
	ip_file="/tmp/update-clients-ip.${domain}"
	ip_file_log="${ip_file}.log"
	ip_file_old="${ip_file}.old"
	ip_file_new="${ip_file}.new"

	mv -f "${ip_file_new}" "${ip_file_old}" 2>/dev/null
	dig +short @ns1.example.net "${domain}" > "${ip_file_new}"
	diff -N "${ip_file_old}" "${ip_file_new}" > /dev/null

	if [ $? -eq 1 ]; then
		echo -n "`date -R` " >> "${ip_file_log}"
		cat "${ip_file_new}" >> "${ip_file_log}"

		[ -r "${ip_file_old}" ] && cat "${ip_file_old}" | xargs -I ip ipset -exist del clients ip
		[ -r "${ip_file_new}" ] && cat "${ip_file_new}" | xargs -I ip ipset -exist add clients ip
	fi
done

注意修改其中 ns1.example.net 为你自己的 name server。

添加文件 /usr/local/etc/clients.txt,文件内容为你的客户端的域名列表:

yourclient1.example.net
yourclient2.example.net

设置开机时自动运行 iptables 相关脚本,在 /etc/rc.local 的 exit 0 之前添加如下代码:

/usr/local/bin/iptables.sh
/usr/local/bin/update-clients-ip.sh

定时运行 update-clients-ip.sh,在 /etc/crontab 里增加:

* *	* * *	root	/usr/local/bin/update-clients-ip.sh

可以使用命令 ipset list clients 来查看 clients 里有哪些 IP 地址。

#crontab, #ddns, #ipset, #iptables, #rc-local, #shadowsocks-libev, #ubuntu