和号称下一代VPN协议的WireGuard相比,N2N是一个经历了多年验证的p2p组网工具,可满足小规模机器集群的VPN使用需求。

N2N的版本

N2N目前主要有n2n_v1, n2n_v2,n2n_v2s三个版本,v1加密等级低速度快,v2加密等级高速度慢。v2s是meyerd对v2版本的强化,更稳定,更容易直连,因此一般选择v2s版本。n2n_v2.4是n2n作者ntop在经历数年停更后的再一次翻新,目前尚不稳定,不推荐使用。

n2n适用于Unix系和Windows系的多个平台,可以通过在不同平台编译,生成对应版本。n2nwinGui是windows平台的一个带UI的发行版本,hin2n是对应的Android手机的发行版本。

编译安装

安装比较简单,网络上的教程也很多,关键在于组网的所有机器使用统一版本的n2n.在本文中,我们统一安装N2N_v2s版本。

Linux安装

#需要cmake工具支持,如未安装,运行yum install cmake 进行安装
#下载代码
cd /usr/src/
git clone https://github.com/meyerd/n2n
#创建编译生成目录
cd n2n_v2
mkdir build && cd build
#编译
cmake ..
make
#安装
make install

Windows安装

首先安装cmake工具。在官网下载对应版本的cmake安装包,点击按照提示一步步安装。N2N代码需要使用MingW交叉编译,因此还需要安装MingW编译器。下载MingW安装工具,安装mingw-base, mingw-gcc-g++, msys-base三个组件。 可以通过运行${mingw_dir}\msys\1.0\msys.bat检测cmake是否安装成功,如果提示未发现命令,请检查环境变量是否包含cmake安装目录。

rem 下载代码
cd /e/src/
git clone https://github.com/meyerd/n2n
cd n2n/n2n_v2/

rem 编译
mkdir build && cd build
cmake -G "MSYS Makefiles" --build ./ ../
make

#编译后生成edge.exe supernode.exe两个应用程序

此时,已经可以通过命令行运行supernode.exe 和edge.exe, 如果需要UI界面,请下载安装n2nguien.exe,并使用编译好的edge.exe 替换安装目录中的edge2.exe.

Android手机安装

下载hin2n安装包进行安装。配置和n2nguien.exe配置类似。

启动服务端

#${supernode_port}可为大于4000的任意端口,注意启动客户端时,所有连入网络的客户端网络名称和密码应该保持一致 
supernode -l ${supernode_port}

#其他各项参数含义可使用-h选项查看,-f可以以后台程序启动supernode

启动客户端

在Linux环境或者Windows命令行环境中,直接运行下面的命令启动N2N客户端。

#常用参数分别是-M MTU, -l supernode地址:端口,-a 虚拟局域网本地地址,-L 本地公网出口ip,用于帮助直连,-c 网络名称,-k 加密密码
edge -M 1400 -l ${server_ip}:${server_port} -a ${local_ip} -L ${interface_of_public_net} -c ${network_name} -k ${encrypt_password}

如果windows版的客户端使用N2N Gui, 那么在界面配置对应的参数。主要的参数对应关系为: -l = IP address + Port;  -a = Assigned IP;  -c = Group name; -k = password.

参数说明

-d 虚拟网卡名,指定由edge命令创建的TAP虚拟接口的名字
-a [static:|dhcp:]指定分配给TAP接口的虚拟网段(IP),static模式其实可以不用加那个static: 直接写IP就行。如果使用DHCP,需要在其中边缘节点上配置一台DHCP服务器,使用“-a dhcp:x.x.x.x”选项来代替
-c 用于区分节点的VPN社区(组)名,最大长度为16字节。可以用来在同样一组节点中创建多个VPN
-k 用于twofish加密的秘钥字符串,如果想要从命令行中隐藏秘钥,可以使用N2N_KEY环境变量。
-K 用于加密的Key文件,和-k不能共存
-s 子网掩码
-l supernode的IP:端口,可以指定不超过两个supernode的监听地址和端口号,比如(-l <supernodeA> -l <supernodeB>)。
-i NAT打洞间隔
-b 当使用DHCP时定期刷新IP
-p 指定本地端口
-u 指定运行所用的UID(windows不适用)
-g 指定运行所用的GID(windows不适用)
-f 前台运行(windows不适用)
-m 为虚拟网卡指定静态MAC地址,不使用这个参数的话,edge 命令将会随机生成一个 MAC 地址。事实上,为一个 VPN 接口强制指定一个静态的 MAC 地址是被强烈推荐的做法。否则,比如当你在一个节点上重启了 edge 守护程序的时候,其它节点的 ARP 缓存将会由于新生成的 MAC 地址而遭到污染,它们将不能向这个节点发送数据,直到被污染的 ARP 记录被消除。
-r 启用n2n网络包转发,当-a指定DHCP时需要启用
-E 接收组播MAC地址
-v 输出比较详细的log
-t 指定用于管理的UDP端口

设置开机自动启动

Linux通过在init.d 目录下创建edge 的软连接,实现开机自动启动。Windows通过在事件管理中添加开机事件任务实现其自动启动,运行cmd启动edge客户端。如果使用了n2ngui之类的gui客户端,可启动客户端程序。详情可百度Linux和Windows开机启动程序的实现。

Linux下的自动启动脚本一个例子如下:

#!/bin/bash
#
# n2nvpn start edge client
# !!!chkconfig is not supported by edge!!!
# !!!try start it in /etc/rc.d/rc.local!!!
# chkconfig: 23456 99 01
# description: n2n vpn client
### BEGIN INIT INFO
# Provides: $wangc
### END INIT INFO

# Source function library.
. /etc/init.d/functions

PRG=/usr/local/sbin/edge
#CONF=/etc/fdfs/tracker.conf
CONF="-a ${edge_address} -l ${supernode_address} -c ${community_name} -k ${password}"

if [ ! -f $PRG ]; then
  echo "file $PRG does not exist!"
  exit 2
fi

#if [ ! -f $CONF ]; then
#  echo "file $CONF does not exist!"
#  exit 2
#fi

CMD="$PRG $CONF"
RETVAL=0

start() {
        echo -n $"Starting FastDFS tracker server: "
        $CMD &
        RETVAL=$?
        echo
        return $RETVAL
}
stop() {
        #$CMD stop
        pid = `pgrep 'edge'`
        RETVAL=$?
        if [ $RETVAL -eq 0 ]; then
                kill $RETVAL
                RETVAL=$?
        else
                echo "edge is not started"
        fi
        return $RETVAL
}

rhstatus() {
        #status fdfs_trackerd
        pid = `pgrep 'edge'`
        RETVAL=$?
        if [ $RETVAL -eq 0 ]; then
                if [ ! pid -eq '']; then
                        echo "edge is running"
                fi
        else
                echo "edge is not running"
                RETVAL=1
        fi
        return $RETVAL
}
restart() {
        #$CMD restart &
        stop
        start
}


case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        rhstatus
        ;;
  restart|reload)
        restart
        ;;
  condrestart)
        restart
        ;;
  *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart}"
        exit 1
esac

exit $?


DHCP配置

dhcp必然是一个n2n的edge节点。在其中一个n2n节点上安装dhcp服务器。启动dhcp服务。然后在其他edge节点启动时配置选项 -r -a dhcp:0.0.0.0.

故障诊断

可通过在启动是添加 -v -f 选项进入edge和supernode的调试模式,注意重新启动前需要杀掉之前启动的进程,防止出现资源已被占用错误。

#supernode 调试模式
supernode -l ${supernode_ip:supernode_port} -v -f
#edge 调试模式
edge -a ${local_ip} -c ${network_id} -k ${encrypt_passwd} -l \ 								${supernode_ip}:${supernode_port} -v -f

编译过程中出现‘cc1’ is not found之类的错误

此错误产生是由于cc1不在标准位置引起的,有两种解决方案,一种是找到cc1的位置

find / -name cc1

然后将其路径加入环境变量$PATH

#在/etc/profile末尾添加
$PATH=$PATH:${path_to_cc1}

#记得重新应用系统配置
source /etc/profile

另外一种是重新安装gcc,gcc-c++或者从外部复制对应的cc1文件到标准文件夹下

#文件夹路径大概在
/usr/libexec/gcc/4.8.2/ 
#也可用find命令查找对应路径
find /usr -name gcc

调试出现 sendto: Operation not Permitted错误

此错误是防火墙引起的,请在防火墙中开放端口出连接。

iptables -I OUTPUT 1 -p udp --dport ${supernode_port} -j ACCEPT

远程不能连接

可以用netcat测试远程udp端口是否打开,根据命令输出修改防火墙或检查远程计算机网络

nc -vuz ${supernode_ip} ${supernode_port}

测试tcp端口使用telnet

提升权限的方法

#1 sudo 命令
sudo ${cmd}
#2 切换到root用户
su -
#如果ssh无法登陆root用户,请到etc/sshd/ 下修改config文件中的配置项

windows机器ping Linux机器可以ping通,反向不通

关掉window的防火墙,看是否能ping通。如果可以,则说明是windows防火墙的问题,在防火墙中添加规则,允许公网的回显请求通过。

ping断断续续超时

修改MTU值为1300,或可解决。

单向能ping通,反向ping不通,也无法连接其他服务

注意关闭windows防火墙。