简介

虚拟子网软件,类似于OpenWPN,使用虚拟网卡,但是只支持UDP协议连接,配置简单。在Kernel 5.6之后已经内置。

中继服务器

作为中继服务器(Bounce Server),和普通的对等节点一样,它能够在 NAT 后面的客户端之间充当中继服务器,可以将收到的任何子网流量转发到正确的对等节点,这个过程并非由WireGuard处理,而是由系统内核和iptables处理的。公网可达的子网不需要中继服务器,只有当有节点位于 NAT 后面时才需要。

在WireGuard里客户端和服务端的功能是平等的,差别只是谁主动连接谁而已。如果双方都在监听端口,谁主动连接,谁就是客户端。主动连接的一方需要预知对方的公网地址和端口(Endpoint),被动连接的一方则不需要。如果双方都位于NAT后面,则需要加一个中继节点,双方都以中继服务器作为对等节点,它们的通信流量会先进入中继服务器,然后再转发给对方。

如果某一端同时连接了多个对端,当它想访问某个IP时,如果有具体的路由可用,则优先使用具体的路由,否则就会将流量转发到中继服务器,中继服务器再根据系统路由表进行转发。可以通过检查wg show wg0route找到WireGuard对一个给定地址的路由方式。

安装

服务器

参考https://www.iplayio.cn/post/70750984https://www.cnblogs.com/a5idc/p/13895146.htmlhttps://yooooex.com/2019/05/23/wireguard-deploy/

ubuntu安装

sudo apt install wireguard

centos7安装

yum install epel-release
yum provides wg-quick
yum install wireguard-tools

打开转发

sudo vi /etc/sysctl.conf
# 取消这行的注释
net.ipv4.ip_forward=1
# 保存文件并应用更改
sudo sysctl -p
# 输出:net.ipv4.ip_forward = 1

配置防火墙
Ubuntu: 如果启用了UFW,需要添加规则,本例使用的端口是50004

# 添加端口
sudo ufw allow 50004/udp
# 查看
sudo ufw status verbose

Centos7

firewall-cmd --zone=public --add-port=50004/udp --permanent
firewall-cmd --reload

配置

# 生成公私钥, 如果是对本机进行初始化, 先cd到/etc/wireguard目录下
umask 077
wg genkey | tee private.key | wg pubkey > public.key
# 创建新文件wg0.conf, 这个是服务wg-quick@wg0默认使用的配置文件. 添加以下内容:
sudo vi /etc/wireguard/wg0.conf
# ==================== begin ===================
[Interface]
PrivateKey = [填入服务端私钥]
Address = 10.253.0.1/24
ListenPort = 50004
# 规则说明:接受来源为%i的转发;接受出口为%i的转发;增加对出口为本机网卡的NAT映射
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens160 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens160 -j MASQUERADE[Peer]
PublicKey = [填入客户端公钥]
# 允许客户端使用的IP段,对于peer的隧道IP, 建议使用/32的固定IP, 以避免和其他peer重复导致无法连接
AllowedIPs = 10.253.0.2/32
# ===================== end ====================# 启动wg0
sudo wg-quick down wg0
# 停止wg0
sudo wg-quick up wg0
# 查看
sudo wg
# 查看单个
sudo wg show wg0

启动停止路由规则中加上对IPv6的支持

# 启动动作, 要把 ens160 替换成自己的网口名称
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens160 -j MASQUERADE; ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -A FORWARD -o %i -j ACCEPT; ip6tables -t nat -A POSTROUTING -o ens160 -j MASQUERADE
# 关闭动作
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens160 -j MASQUERADE; ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -D FORWARD -o %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o ens160 -j MASQUERADE

设置为自启动

systemctl enable wg-quick@wg0

命令行客户端

先生成公私钥,然后使用配置文件

[Interface]
PrivateKey = [客户端私钥]
Address = 10.253.0.2/24
DNS = 114.114.114.114[Peer]
PublicKey = [服务端公钥]
# 允许通过的IP段,如果设为0.0.0.0/0则拦截本机所有流量
AllowedIPs = 192.168.16.0/24,10.253.0.0/24
Endpoint = [服务器的IP]:50004
PersistentKeepalive = 25

注意

  • 如果这个客户端是作为逆向穿透的节点

    • [Interface]中增加PostUp, PostDown, 但是不需要DNS;
    • [Interface]中Address掩码可以使用/24也可以使用/32
    • [Peer]中增加PersistentKeepalive
  • 如果这是Windows Wireguard客户端
    • [Interface]中不需要PostUp, PostDown, 可以不需要DNS;
    • [Interface]中Address掩码使用/24, 否则会出现连接不上服务端的情况(本地显示已连接, 但是服务端看不到, 并且接收字节为0)
    • [Peer]中只需要PublicKey, AllowedIPs, Endpoint

Ubuntu20.04客户端(通过NetworkManager)

NetworkManager界面对Wireguard的支持, 要到版本1.26之后, 如果是Ubuntu20.04, 需要自己编译.

sudo apt install wireguard git dh-autoreconf libglib2.0-dev intltool build-essential libgtk-3-dev libnma-dev libsecret-1-dev network-manager-dev resolvconf

从Github clone对应的项目

git clone https://github.com/max-moser/network-manager-wireguard
cd network-manager-wireguard
./autogen.sh --without-libnm-glib./configure --without-libnm-glib --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib/x86_64-linux-gnu --libexecdir=/usr/lib/NetworkManager --localstatedir=/varmake
sudo make install

然后在网络配置界面的WPN中点击+号, 就能看到Wireguard的选项了. 配置说明

  • Identity

    • Name: 可以使用wg0之类的名称, 这个会被用于网口名称, 所以不要太长太复杂
    • Interface:
      • Address(IPv4): 10.253.0.4/32 这个是开启wg之后本机的隧道IP
      • Address(IPv6): 可以留空
      • Listen Port: 可以留空, 也可以指定为50004
      • Private Key: 本机的私钥
      • 其他都可以留空
    • Peer
      • Public Key: 服务端的公钥
      • Allow IPs: 需要走隧道的IP段, 一般包含隧道自身IP段, 以及要借道隧道的IP段, 但是这里设置并不会产生对应的route
      • Endpoint: 服务端的IP和端口
      • Persis.Keepalive: 25 保持活动的时间间隔
      • 其他都可以留空
  • IPv4
    • IPv4 method: Automatic (DHCP) 实际产生的IP还是之前在Identity->Interface中配置的IP地址
    • DNS: Automatic
    • Routes: 取消Automatic, 添加
      • 10.253.0.0, 255.255.255.0, 10.253.0.102, 5 将10.253.0.0/24这个段的路由, 设置到10.253.0.102(即本机的隧道网口)上
      • 192.168.13.0, 255.255.255.0, 10.253.0.102, 5 将192.168.13.0/24这个段的路由也设置到本机隧道网口上
      • 如果还有其他需要走隧道的IP段, 则继续添加.
    • 不勾选Use this connection only for resources on its network

注意: 如果不手动添加路由, 在启动此wg网口后, 本机路由没有变化, 访问不生效, 但是通过ping 10.253.0.1 -I wg0可以ping通服务端隧道IP, 说明仅是路由的问题.

配置说明

关于AllowedIPs

Wireguard的AllowedIPs因为涉及服务端和客户端的允许IP范围,需要理清一下这个设置的含义

  • 首先,AllowedIPs会影响当前机器的路由设置,在AllowedIPs配置的每一段IP,都会在路由表里指向这个wireguard网卡
    那么在A节点,如果你要访问B节点后面的网络,你就要把B节点后面网络的IP段,配到Peer.B下面去
  • 其次,提供转发的节点,不需要关心从各个节点到来的流量要访问何处,不需要为自身转发的目标网段配置AllowedIPs
    比如A节点处于5.5.5.0/24网段,A已经提供了转发,那么A不需要在自己节点下面的Peer的AllowedIPs中配置5.5.5.0/24

服务端和客户端的[Peer]中配置的AllowedIPs

  • 无论哪一端,AllowedIPs的IP段都会加入路由表
  • AllowedIPs需要包含对方节点的隧道IP
  • AllowedIPs需要包含对方节点提供转发的IP网段,这将通过增加路由规则拦截本机对这些IP范围的访问流量
  • 当配置的AllowedIPs为0.0.0.0/0时,会将虚拟网卡的Default Gateway设为0.0.0.0,而不是通过路由表

公网中继的AllowedIPs配置问题

使用公网中继节点进行穿透时(例如R为公网中继, A为工作区内网节点, B为个人接入),
如果AllowedIPs配置不正确, 会导致B->R, R->A都能访问, 但是B->A就无法访问的问题. 需要检查A节点的配置, 检查其中R这个节点的[Peer]配置中AllowedIPs是否未包含B节点的隧道IP.
举例:R节点 有公网IP, 提供前往192.168.116.x和192.168.117.x的中转

[Interface]
Address = 10.253.0.1/32
...
[Peer]
AllowedIPs = 10.253.0.3/32,192.168.117.0/24

A节点 处于192.168.117.0/24的内网

[Interface]
Address = 10.253.0.3/32
[Peer]
AllowedIPs = 10.253.0.1/32,192.168.116.0/24
Endpoint = xx.xx.xx.xx:10004

B节点 个人外网接入, 需要访问192.168.117.0/24网段

[Interface]
Address = 10.253.0.101/24
[Peer]
AllowedIPs = 192.168.116.0/24, 10.253.0.0/24, 192.168.117.0/24
Endpoint = xx.xx.xx.xx:10004

这时候就会出现前面提到的情况, B->RR->A访问都通但是B->A访问不通, 需要将A配置中R的AllowedIPs改为10.253.0.1/24才行, 如下所示.

[Interface]
Address = 10.253.0.3/32
[Peer]
AllowedIPs = 10.253.0.1/24,192.168.116.0/24
Endpoint = xx.xx.xx.xx:10004

或者更进一步, 仅仅将B节点和R节点的IP放入, 如下所示, 这样就只允许B->R->A, 其他节点连接到R之后, 无法访问A

[Interface]
Address = 10.253.0.3/32
[Peer]
AllowedIPs = 10.253.0.1/32,10.253.0.101/32,192.168.116.0/24
Endpoint = xx.xx.xx.xx:10004

关于PresharedKey

即PSK 预共享密钥,节点可以给连接自己的每一个peer都分配一个PSK,这个PSK会设置在每对节点的[Peer]中,连接时检查是否一致

# 生成(每个peer一个)
wg genpsk > presharedkey
# 配置格式
[Peer]
PublicKey    = P556VVMhhBb+kc2Gm7JV46jh1oRv75YscK8q131iSnM=
PresharedKey = oZ33KPYBwo7aFyxewm5Eutlelztz9lXQ2Z8tyouc7TM=
AllowedIPs   = 10.253.0.0/24
Endpoint     = 123.123.123.123:31231
...

关于PersistentKeepAlive

这个参数用于内网节点定期发送报文以保持连接。默认情况下WG尽量保持沉默以避免发送太多数据,但是如果连接中一些节点处于内网或防火墙后,在长时间无数据后连接可能被防火墙关闭,此时如果外网节点需要发送数据,会发现连接不可用。这种情况下就需要内网节点定期主动发送数据以保持连接。
注意:这个参数与最后握手时间是不一样的。一次握手会建立一个约三分钟长度的会话时间,在这个会话时间内,发送keep-alive报文不需要再次建立会话。在实际使用中,如果发送报文时会话时间已经剩余不到1分钟,会在此会话到期前就创建一个新的会话。正常情况下,如果PersistentKeepAlive设为了25,握手时间基本上不会超过3分钟,除非处于移动设备上,因为设备节电等原因导致发送时间滞后等情况。

关于DNS

客户端如果配置为全流量拦截(0.0.0.0/0),则必须设置DNS项,如果不配置DNS,在连接后会不能正确解析域名

关于子网间穿透

Wireguard可以配置通过一个公共服务器同时连接多个子网。这时候需要在服务器和每个子网节点上,都配置同一个网段的隧道IP和相应的路由,可以参考https://anyisalin.github.io/2018/11/21/fast-flexible-nat-to-nat-vpn-wireguard/ 主要的设置有三处:

  1. 服务器和子网节点: 在sysctl中开启ip forward
  2. 服务器和子网节点: 在[Interface]中增加PostUp和PostDown的路由设置
  3. 服务器: 需要设置一下端口号,并在防火墙中打开此端口
  4. 服务器和子网节点如果安装了firewalld, 还需要在firewalld中开启masquerade
firewall-cmd --permanent --zone=public --add-masquerade
firewall-cmd --reload

Windows节点
windows做这个穿透会比较复杂,因为windows不像linux那样有iptables可以配置,需要设置的可以参考这篇 https://www.henrychang.ca/how-to-setup-wireguard-vpn-server-on-windows/

命令行操作(使用wireguard-go)

对于某些环境不适合用原生wireguard的, 可以使用wireguard-go代替, wireguard-go只是用于创建wg网卡, 其他的命令还是用wg来完成的. 以下是纯命令行的操作.

wireguard-go创建网口, 配置IP

# 使用wireguard-go生成虚拟网卡
sudo ./wireguard-go wg0# 查看创建的网卡ip linkip link show dev "wg0"# 删除创建的网卡sudo ip link del wg0# 给虚拟网卡添加地址
sudo ip address add dev wg0 10.253.0.4/24
sudo ip -4 address add dev "wg0" "10.253.0.4/24"# 删除地址sudo ip addr del dev wg0 192.168.0.193/24

wg对wg0进行配置

# 生成服务端的公私钥
wg genkey | sudo tee /etc/wireguard/privatekey | wg pubkey | sudo tee /etc/wireguard/publickey# 设置监听端口
sudo wg set wg0 listen-port 50001
# 设置节点私钥
sudo wg set wg0 private-key /etc/wireguard/privatekey
# 查看wg状态
sudo wg
# 或者
sudo wg show# 查看wg配置 - 这个会输出格式化的配置信息, 可以存为conf文件
sudo wg showconf wg0
# 从wg0.conf.bak载入配置到wg0, 会覆盖当前配置, 且重置当前的连接
sudo wg setconf wg0 wg0.conf.bak
# 从wg0.conf.bak的配置添加到wg0
sudo wg addconf wg0 wg0.conf.additional
# 从wg0.conf.bak中读取配置, 将变化部分应用到wg0, 不如setconf高效, 但是不会影响到当前存在的会话
sudo wg syncconf wg0 wg0.conf.additional# 启动虚拟网卡
sudo ip link set dev wg0 up# 断开网卡sudo ip link set dev wg0 down# 添加远程节点 (此时远程节点也要添加对应此节点的配置)
sudo wg set wg0 peer PasdfeghBb+kadem7JVtbjh1oRv75Ysc123451iSnM= allowed-ips 192.168.36.0/24,10.253.0.0/24 endpoint 114.104.11.76:50001 persistent-keepalive 30# ping检查(远程节点IP), 远程也ping此节点检查ping 10.253.0.1# 删除远程节点sudo wg set <interface> peer <key> remove

配置路由和iptables

# 增加本地路由至虚拟网卡
sudo ip -4 route add "192.168.36.0/24" dev "wg0" table "$TABLE"
sudo ip route add 192.168.36.0/24 dev wg0# 删除路由sudo ip route del 192.168.36.0/24 dev wg0# ping检查ping 192.168.36.109# 增加iptables规则(如果需要从远程访问本地子网)
iptables -A FORWARD -i wg0 -j ACCEPT
iptables -A FORWARD -o wg0 -j ACCEPT
iptables -A -t nat POSTROUTING -o eth0 -j MASQUERADE
ip6tables -A FORWARD -i wg0 -j ACCEPT
ip6tables -A FORWARD -o wg0 -j ACCEPT
ip6tables -A -t nat POSTROUTING -o eth0 -j MASQUERADE# 对应的删除命令iptables -D FORWARD -i wg0 -j ACCEPTiptables -D FORWARD -o wg0 -j ACCEPTiptables -D -t nat POSTROUTING -o eth0 -j MASQUERADEip6tables -D FORWARD -i wg0 -j ACCEPTip6tables -D FORWARD -o wg0 -j ACCEPTip6tables -D -t nat POSTROUTING -o eth0 -j MASQUERADE

使用TCP来避免防火墙的UDP规则影响

可以使用udptunnelhttps://gist.github.com/insdavm/90cbeffe76ba4a51251d83af604adf94
或者udp2raw-tunnelhttps://github.com/wangyu-/udp2raw-tunnel
以及TunSafehttps://github.com/TunSafe/TunSafe

后两者有支持windows和android的客户端
实现思路是在服务端运行一个TCP隧道, 代理wg的端口, 在客户端运行TCP隧道的客户端, 连接到服务端的TCP隧道, 客户端的wg连接本地端口

iptables规则

单包验证SPA规则

# 清空iptables
iptables -F
# 已经建立的tcp连接允许通过 -m state --state ESTABLISHED 只针对tcp
iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
# 允许访问udp 62201端口
iptables -A INPUT -p udp --dport 62201  -j ACCEPT
# 允许22端口通过
iptables -A INPUT -p tcp --dport 22  -j ACCEPT
# 允许入包回环
iptables -A INPUT -i lo -j ACCEPT
# 出包的tcp
iptables -A OUTPUT -m state --state ESTABLISHED -j ACCEPT
# 出包的udp
iptables -A OUTPUT -p udp -j ACCEPT
# 允许出包回环
iptables -A OUTPUT -o lo -j ACCEPT
# 允许建立的FORWARD通过
iptables -A FORWARD -m state --state ESTABLISHED -j ACCEPT
# 最后一步 关闭IMPUT,OUTPUT,FORWARD
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

其他

提供内核支持的发行版

在Ubuntu20.04最近的更新中, Kernel已经升级到5.8.0, 自带了wireguard

~$ uname -a
Linux milton-t550 5.8.0-43-generic #49~20.04.1-Ubuntu SMP Fri Feb 5 09:57:56 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
~$ sudo modprobe wireguard
[sudo] password for milton:
~$ lsmod
Module                  Size  Used by
wireguard              86016  0
curve25519_x86_64      49152  1 wireguard
libchacha20poly1305    16384  1 wireguard
chacha_x86_64          28672  1 libchacha20poly1305
poly1305_x86_64        28672  1 libchacha20poly1305
libblake2s             16384  1 wireguard
blake2s_x86_64         20480  1 libblake2s
ip6_udp_tunnel         16384  1 wireguard
udp_tunnel             16384  1 wireguard

Debug日志

启用WireGuard debug

echo 'module wireguard +p' | sudo tee /sys/kernel/debug/dynamic_debug/control

Disable WireGuard debug

echo 'module wireguard -p' | sudo tee /sys/kernel/debug/dynamic_debug/control

查看输出

dmesg
# or
journalctl -f

性能测试

https://www.reddit.com/r/linux/comments/9bnowo/wireguard_benchmark_between_two_servers_with_10/
对Wireguard性能的测试, 比较的对象是直接传输和OpenVPN. 用netperf在MTU8500~9000的情况下, 三者的速度对比是44:23:1

netperf -t TCP_STREAM -l 600 -H 10.0.9.11

Wireguard笔记相关推荐

  1. Wireguard笔记(三) lan-to-lan子网穿透和多网段并存

    目录 Wireguard笔记(一) 节点安装配置和参数说明 Wireguard笔记(二) 命令行操作 Wireguard笔记(三) lan-to-lan子网穿透和多网段并存 多 Wireguard 服 ...

  2. 【读书笔记】知易行难,多实践

    前言: 其实,我不喜欢看书,只是喜欢找答案,想通过专业的解答来解决我生活的困惑.所以,我听了很多书,也看了很多书,但看完书,没有很多的实践,导致我并不很深入在很多时候. 分享读书笔记: <高效1 ...

  3. 【运维学习笔记】生命不息,搞事开始。。。

    001生命不息,搞事不止!!! 这段时间和hexesdesu搞了很多事情! 之前是机械硬盘和固态硬盘的测速,我就在那默默的看着他一个硬盘一个机械测来测去. 坐在他后面,每天都能看到这位萌萌的小男孩,各 ...

  4. SSAN 关系抽取 论文笔记

    20210621 https://zhuanlan.zhihu.com/p/353183322 [KG笔记]八.文档级(Document Level)关系抽取任务 共指id嵌入一样 但是实体嵌入的时候 ...

  5. pandas以前笔记

    # -*- coding: utf-8 -*- """ Created on Sat Jul 21 20:06:20 2018@author: heimi "& ...

  6. PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call

    您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...

  7. 容器云原生DevOps学习笔记——第三期:从零搭建CI/CD系统标准化交付流程

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  8. 容器云原生DevOps学习笔记——第二期:如何快速高质量的应用容器化迁移

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  9. 王道考研 计算机网络笔记 第六章:应用层

    本文基于2019 王道考研 计算机网络: 2019 王道考研 计算机网络 个人笔记总结 第一章:王道考研 计算机网络笔记 第一章:概述&计算机网络体系结构 第二章:王道考研 计算机网络笔记 第 ...

  10. 王道考研 计算机网络笔记 第五章:传输层

    本文基于2019 王道考研 计算机网络: 2019 王道考研 计算机网络 个人笔记总结 第一章:王道考研 计算机网络笔记 第一章:概述&计算机网络体系结构 第二章:王道考研 计算机网络笔记 第 ...

最新文章

  1. SQL 中字母大小写转换
  2. 基于深度学习网络的运动想象BCI系统及其应用
  3. iptables的表和链结构详解
  4. python好学吗mooc中文网-2020年大学mooc用Python玩转数据作业答案
  5. mysql codesmith_CodeSmith连接Mysql配置
  6. 基于ABP落地领域驱动设计-04.领域服务和应用服务的最佳实践和原则
  7. coding ssh_exchange_identification: Connection closed by remote host
  8. 请概述可视化卷积神经网络的中间输出的基本思想。_最详细的卷积神经网络入门指南!...
  9. 超过12000个零件,钢琴就是一部复杂的机器
  10. new 对象时的暗执行顺序
  11. javascript的jQuery库小结(1)
  12. Linux 配置网络
  13. RK3288_Android7.1调试RTC总结(一)
  14. Redis RDB持久化和AOF持久化及恢复测试
  15. 中兴云桌面服务器,中兴云桌面解决方案.pdf
  16. asio ssl 笔记
  17. 大学计算机课英语心得体会,【大学计算机课程总结12篇】_大学计算机课程总结范文大全_2021年大学计算机课程总结_东城教研...
  18. uc缓存分段视频合并
  19. 原来我们都让历史书骗了- -#!~
  20. 使用ESP32连接腾讯云实现远程控制方法

热门文章

  1. 工业自动化控制-组态王1
  2. 计算机科学导论课后感,计算机科学导论课后总结_5
  3. Sentence2vec
  4. 服务器dell/hp/ibm硬件检测工具
  5. 戴尔服务器硬件查看信息工具omreport
  6. php dbc2000操作类,超详细菜鸟入门第一课DBC2000详细架设
  7. 2017年5月13日 恒生电子笔试题
  8. 软件测试流程改进的几点看法
  9. 数据库系统原理及mysql应用教程_数据库系统原理及MySQL应用教程
  10. pandorabox开启ssr_潘多拉固件开启UPNP的方法(图文教程)