虚拟网络

network namespace

是什么?

当前系统的网络空间,拥有单独的网络协议栈,网络设备、网卡、路由表、转发表、ARP表、ip地址表、iptables、socket等与网络有关的组建均独立,就像进入了另一个网络环境
且该网络空间可以实现交换机、路由器、防火墙等功能

使用netns在linux系统上搭建网络

bridge1
网络描述
该网络由四部分组成:外网、虚拟网络空间net0、虚拟网络空间net1、虚拟网络空间net2
net0和net2分别为网段10.0.1.0/24 10.0.2.0/24的网络空间,并且接入网桥
net1为网络空间,分别以接口eth0和eth1接入虚拟网桥,分别和net0和net2同一个网段
net1为网络空间,以eth2接入网桥,和物理接口enp0s8同一个网段
enp0s8为虚拟机的桥接物理网卡(虚拟机接口混杂模式开启)
192.168.55.165物理机器,接入虚拟机虚拟bridge另外一端均属于ubuntun虚拟机上搭建虚拟网络
淡黄色部分属于虚拟网桥
net0和net2的默认网关是net1
net1的默认网关是办公网络交换机192.168.55.254
经过net1出去流量做snat

搭建网络最终效果
net0和net1和net2 网络空间中均可以上外网

搭建命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
root@controller-VirtualBox:/home/controller# cat br2.sh


#new bridge & start
ip addr flush dev enp0s8
brctl addbr br0
brctl addif br0 enp0s8
ifconfig br0 192.168.55.244/24 up
ip route add default via 192.168.55.254

# ip link add br0 type bridge
# ip link set dev br0 up

#add net0:eth0 <-> br0:tap0
ip link add net0_eth0 type veth peer name tap0
ip netns add net0
ip link set dev net0_eth0 netns net0
ip netns exec net0 ip link set dev net0_eth0 name eth0
ip netns exec net0 ip addr add 10.0.1.1/24 dev eth0
ip netns exec net0 ip link set dev eth0 up
ip link set dev tap0 master br0
ip link set dev tap0 up

#add net1:eth0 <-> br0:tap1
ip link add net1_eth0 type veth peer name tap1
ip netns add net1
ip link set dev net1_eth0 netns net1
ip netns exec net1 ip link set dev net1_eth0 name eth0
ip netns exec net1 ip addr add 10.0.1.2/24 dev eth0
ip netns exec net1 ip link set dev eth0 up
ip link set dev tap1 master br0
ip link set dev tap1 up

#add net2:eth0 <-> br0:tap2
ip link add net2_eth0 type veth peer name tap2
ip netns add net2
ip link set dev net2_eth0 netns net2
ip netns exec net2 ip link set dev net2_eth0 name eth0
ip netns exec net2 ip addr add 10.0.2.1/24 dev eth0
ip netns exec net2 ip link set dev eth0 up
ip link set dev tap2 master br0
ip link set dev tap2 up

#connect net2:eth1 <-> br0:tap3
ip link add net2_eth1 type veth peer name tap3
ip link set dev net2_eth1 netns net1
ip netns exec net1 ip link set dev net2_eth1 name eth1
ip netns exec net1 ip addr add 10.0.2.2/24 dev eth1
ip netns exec net1 ip link set dev eth1 up
ip link set dev tap3 master br0
ip link set dev tap3 up

#add route
#ip netns exec net2 ip route add 10.0.1.0/24 via 10.0.2.2 dev eth0
#ip netns exec net0 ip route add 10.0.2.0/24 via 10.0.1.2 dev eth0

ip netns exec net2 route add default gw 10.0.2.2
ip netns exec net0 route add default gw 10.0.1.2

#open gateway forward
ip netns exec net1 sysctl net.ipv4.ip_forward=1


#connect net1:eth2 <-> br0:tap4
ip link add net1_eth2 type veth peer name tap4
ip link set dev net1_eth2 netns net1
ip netns exec net1 ip link set dev net1_eth2 name eth2
ip netns exec net1 ip addr add 192.168.55.233/24 dev eth2
ip netns exec net1 ip link set dev eth2 up
ip link set dev tap4 master br0
ip link set dev tap4 up

#add net1 gateway 192.168.55.254
ip netns exec net1 route add default gw 192.168.55.254

#add snat
ip netns exec net1 iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -o eth2 -j MASQUERADE
ip netns exec net1 iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -o eth2 -j MASQUERADE

ip netns exec net0 ping -c 3 8.8.8.8
ip netns exec net2 ping -c 3 8.8.8.8

Linux虚拟网络设备tun/tap

网络设备概念?

网络设备工作在驱动和协议栈之间,负责衔接它们之间的交互。它帮助驱动和协议栈只关注本身事情。

虚拟网络设备和物理物理设备区别 ?

物理网卡其实就是物理设备,比如物理网卡eth0,它分别连接内核协议栈河外面的物理网络,从物理网络收到的数据包会通过接口转发给内核协议栈,从内核协议栈发出包也会通过物理设备转发最终通过物理网络发出去

虚拟设备和物理设备对于内核网络设备管理模块来讲地位一致且无区别。只不过物理设备往往把数据包送到外网,虚拟设备要看具体实现了。

tun/tap ?

tun/tap连接的应用程序,可以理解其为运行的另一台服务器,这台服务器可用于加密、隧道等数据加工;处理完成后从新借用一个地址将处理完后数据包封装,发出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
+----------------------------------------------------------------+
| |
| +--------------------+ +--------------------+ |
| | User Application A | | User Application B |<-----+ |
| +--------------------+ +--------------------+ | |
| | 1 | 5 | |
|...............|......................|...................|.....|
| ↓ ↓ | |
| +----------+ +----------+ | |
| | socket A | | socket B | | |
| +----------+ +----------+ | |
| | 2 | 6 | |
|.................|.................|......................|.....|
| ↓ ↓ | |
| +------------------------+ 4 | |
| | Newwork Protocol Stack | | |
| +------------------------+ | |
| | 7 | 3 | |
|................|...................|.....................|.....|
| ↓ ↓ | |
| +----------------+ +----------------+ | |
| | eth0 | | tun0 | | |
| +----------------+ +----------------+ | |
|192.168.55.188 | | 10.0.1.1 | |
| | 8 +---------------------+ |
| | |
+----------------|-----------------------------------------------+

Physical Network

上述图表述的应用场景是VPN场景:发到10.0.1.0/24 网络数据通过应用程序B这个隧道,利用192.168.55.188发出到远端。

tun/tap场景下数据包流程

1.应用程序A是一个普通的程序,通过socket A发送了一个数据包,假设这个数据包的目的IP地址是10.0.1.2
2.socket将这个数据包丢给协议栈
3.协议栈根据数据包的目的IP地址,匹配本地路由规则,知道这个数据包应该由tun0出去,于是将数据包交给tun0
4.tun0收到数据包之后,发现另一端被进程B打开了,于是将数据包丢给了进程B
5.进程B收到数据包之后,做一些跟业务相关的处理,然后构造一个新的数据包,将原来的数据包嵌入在新的数据包中,最后通过socket B将数据包转发出去,这时候新数据包的源地址变成了eth0的地址,而目的IP地址变成了一个其它的地址,比如是192.168.55.254
6.socket B将数据包丢给协议栈
7.协议栈根据本地路由,发现这个数据包应该要通过eth0发送出去,于是将数据包交给eth0
8.eth0通过物理网络将数据包发送出去

192.168.55.254收到数据包后,打开数据包,取出原始数据,转发给10.0.1.2,收到10.0.1.2应答后,从新构造应答包并讲原始报文封装里面;走路由返回给程序B,应用程序B解封装,最终将数据包回复给应用程序A

至此一个完整的隧道交互完成了,tun/tap承担了奖协议栈数据包从新交付到应用程序作用,使得数据包有机会在用户态进行封装。

tun另一端是一个用户程序

tun0是一个Tun/Tap虚拟设备,从上图中可以看出它和物理设备eth0的差别,它们的一端虽然都连着协议栈,但另一端不一样,eth0的另一端是物理网络,这个物理网络可能就是一个交换机,
而tun0的另一端是一个用户层的程序,协议栈发给tun0的数据包能被这个应用程序读取到,并且应用程序能直接向tun0写数据。

tun和tap区别

用户层程序通过tun设备只能读写IP数据包,而通过tap设备能读写链路层数据包,类似于普通socket和raw socket的差别一样,处理数据包的格式不一样。

实例解析tun/tap可用于linux用户态从内核查路由重新收到数据包,处理完成后再发出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <linux/if_tun.h>
#include<stdlib.h>
#include<stdio.h>
#include <unistd.h>

int tun_alloc(int flags)
{

struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun";

if ((fd = open(clonedev, O_RDWR)) < 0) {
return fd;
}

memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = flags;

if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
close(fd);
return err;
}

printf("Open tun/tap device: %s for reading...\n", ifr.ifr_name);

return fd;
}

int main()
{

int tun_fd, nread;
char buffer[1500];

/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
* IFF_NO_PI - Do not provide packet information
*/
tun_fd = tun_alloc(IFF_TUN | IFF_NO_PI);

if (tun_fd < 0) {
perror("Allocating interface");
exit(1);
}

while (1) {
nread = read(tun_fd, buffer, sizeof(buffer));
if (nread < 0) {
perror("Reading from interface");
close(tun_fd);
exit(1);
}

printf("Read %d bytes from tun/tap device\n", nread);
}
return 0;
}

执行步骤如下:
(1)linux运行窗口1编译运行tun

1
2
root@controller-VirtualBox:/home/controller# gcc tun.c -o tun
root@controller-VirtualBox:/home/controller# ./tun

(2)linux运行窗口2 查看建立的网络设备tun0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@controller-VirtualBox:/home/controller# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:5f:1b:a9 brd ff:ff:ff:ff:ff:ff
inet 192.168.55.188/24 brd 192.168.55.255 scope global dynamic enp0s8
valid_lft 9908sec preferred_lft 9908sec
inet6 fe80::174:582b:9b7c:3df4/64 scope link
valid_lft forever preferred_lft forever
4: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 500
link/none

(3)linux运行窗口2给tun0配置地址并激活

1
2
3
4
root@controller-VirtualBox:/home/controller# ip addr add 10.0.1.1/24 dev tun0
root@controller-VirtualBox:/home/controller#
root@controller-VirtualBox:/home/controller#
root@controller-VirtualBox:/home/controller# ip link set tun0 up

(4)linux运行窗口2 ping 10.0.1.2

(5)linux运行窗口1 查看出现下面效果,用户态socket已经通过tun0接收到ping包了

1
2
3
4
5
6
7
8
9
10
11
root@controller-VirtualBox:/home/controller# ./tun
Open tun/tap device: tun0 for reading...
Read 48 bytes from tun/tap device
Read 48 bytes from tun/tap device
Read 48 bytes from tun/tap device
Read 84 bytes from tun/tap device
Read 84 bytes from tun/tap device
Read 84 bytes from tun/tap device
Read 84 bytes from tun/tap device
Read 84 bytes from tun/tap device
Read 84 bytes from tun/tap device