Linux虚拟网络之tun(三)隔离网络下的Raw转发
来源:互联网 发布:smartgit linux 安装 编辑:程序博客网 时间:2024/06/12 01:11
在前一篇Linux虚拟网络之tun(二)Raw包转发中,我们在同一个虚机上建立了两个tun网卡,在两个网卡间借用agent_up来ping http_svr。
在实际组网环境中,其实比这个要复杂的多,而且一般也不会是在同一个虚机上的多个网卡间做这种转发(同一个虚机上,直接处理不就完了吗~~~~)。本文在前文基础上,构建一个完全隔离的网络环境,实现内部隧道的建立,转发应用层的报文。
组网模型如下:
稍微有点绕,解释一下(以下将建立和维护这套传输管道的系统简称为系统
):
- client是系统给应用程序(用户)分配的地址。应用程序的上行报文通过client接口传输,系统监听client的所有报文。每个client实际上是用一个tun/tap网卡来实现的。
- 是不是一定要有client?应用程序不能直接发给对外接口网卡吗?其实是可以的。不过有了client接口,一方面会更容易扩展,想象空间更多;一方面接口的处理可能会简单一些。
- 节点2对外接口上收到的上行报文,经过内部协议的处理后,可以直接投递给服务器。在server接口上处理内部协议,还是在节点对外网卡收到包直接处理,其实差别不大,上图的处理稍微简单一些。
- 下行报文处理跟上行正好反过来。
- 限于测试环境,没有多个测试机,所以用容器来隔离。图中的对外接口地址就是容器的地址。
来一份golang的代码:
- common.go 实现一些公用函数
package commonimport ( "fmt" "net")type CommonRecever interface { Read(p []byte) (n int, err error) Close() error}func RunRecever(recever CommonRecever, name string, action func([]byte)) { go func() { buff := make([]byte, 8*1024) for { num, err := recever.Read(buff) if err != nil { fmt.Printf("%s read err: %v \n", name, err) recever.Close() return } action(buff[:num]) } }()}func UdpSender(rip string) (*net.UDPConn, error) { ripaddr, err := net.ResolveUDPAddr("udp4", rip) if err != nil { fmt.Println("net.ResolveUDPAddr ", err) return nil, err } conn, err := net.DialUDP("udp4", nil, ripaddr) if err != nil { fmt.Println("net.DialIP ", err) return nil, err } return conn, nil}func UdpRecver(lip string) (*net.UDPConn, error) { lipaddr, err := net.ResolveUDPAddr("udp4", lip) if err != nil { fmt.Println("net.ResolveUDPAddr ", err) return nil, err } conn, err := net.ListenUDP("udp4", lipaddr) if err != nil { fmt.Println("net.ListenUDP ", err) return nil, err } return conn, nil}
- client.go 客户端代码
package mainimport ( "fmt" "os" "os/exec" "os/signal" "syscall" "common" "github.com/songgao/water")func main() { client, err := water.NewTUN("client") if err != nil { fmt.Println(err) } defer client.Close() // 模拟终端地址1 if err = exec.Command("ip", "addr", "add", "1.1.1.1/32", "dev", "client:0", "peer", "1.1.3.1").Run(); err != nil { fmt.Println(err) } // 模拟终端地址2 if err = exec.Command("ip", "addr", "add", "1.1.1.2/32", "dev", "client:1", "peer", "1.1.3.1").Run(); err != nil { fmt.Println(err) } if err := exec.Command("ip", "link", "set", "dev", "client", "up").Run(); err != nil { fmt.Println(err) } dockerSender, err := common.UdpSender("172.17.0.2:20170") if err != nil { fmt.Println("docker udp sender ", err) } defer dockerSender.Close() dockerRecver, err := common.UdpRecver("172.17.0.1:20170") if err != nil { fmt.Println("docker udp recver ", err) } defer dockerRecver.Close() common.RunRecever(client, "client", func(msg []byte) { dockerSender.Write(msg) }) common.RunRecever(dockerRecver, "docker", func(msg []byte) { client.Write(msg) }) quitChan := make(chan os.Signal) signal.Notify(quitChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, ) <-quitChan}
- server.go 服务端代码
package mainimport ( "fmt" "os" "os/exec" "os/signal" "syscall" "github.com/songgao/water" "common")func main() { fmt.Println("start server!!!") // server interface serverTun, err := water.NewTUN("server") if err != nil { fmt.Println(err) } defer serverTun.Close() if err = exec.Command("ip", "addr", "add", "1.1.3.1/32", "dev", "server:0").Run(); err != nil { fmt.Println(err) } if err := exec.Command("ip", "link", "set", "dev", "server", "up").Run(); err != nil { fmt.Println(err) } if err := exec.Command("ip", "route", "add", "1.1.1.0/24", "dev", "server").Run(); err != nil { fmt.Println(err) } dockerSender, err := common.UdpSender("172.17.0.1:20170") if err != nil { fmt.Println("docker udp sender ", err) } dockerRecver, err := common.UdpRecver("172.17.0.2:20170") if err != nil { fmt.Println("docker udp recver ", err) } fmt.Println("server start handle msg!!!") common.RunRecever(dockerRecver, "docker", func(msg []byte) { serverTun.Write(msg) }) common.RunRecever(serverTun, "server", func(msg []byte) { dockerSender.Write(msg) }) quitChan := make(chan os.Signal) signal.Notify(quitChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, ) <-quitChan}
执行方式:
- 在主机执行 client.go;
- 在容器中执行server.go;
- 在主机执行
ping 1.1.3.1 -I 1.1.1.1
就会执行从 1.1.1.1 到 1.1.3.1 的ping操作; 执行ping 1.1.3.1 -I 1.1.1.2
就会执行从 1.1.1.2 到 1.1.3.1 的ping操作; - 在容器中的1.1.3.1地址上建立一个http的服务器,放几个可供下载的文件,比如 test.zip
在主机上执行
wget --bind-address=1.1.1.1 --no-proxy http://1.1.3.1/test.zip
测试下载遗留问题:
1、如果每个模拟终端是独立的网卡,但是服务器是同一个,那么ping包没问题,下载会涉及到路由问题,无法成功
阅读全文
0 0
- Linux虚拟网络之tun(三)隔离网络下的Raw转发
- Linux虚拟网络之tun(二)Raw包转发
- Linux虚拟网络之tun(四)虚拟VPN
- Linux虚拟网络之tun(一)基本使用
- [转发]网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- Linux 下C 网络编程之 socket RAW
- [转发]网络虚拟化技术(一): Linux网络虚拟化
- 网络虚拟化之FlowVisor:网络虚拟层(下)
- linux下TUN/TAP虚拟网卡的使用
- linux下TUN或TAP虚拟网卡的使用
- linux下TUN/TAP虚拟网卡的使用 - heidsoft
- Windows Azure 虚拟网络中虚拟机的网络隔离选项
- 微信朋友圈,QQ空间,微博等列表展示的功能实现
- 常用插件--bootstrap3-dialog
- WPF不同线程之间的控件的访问
- 第10周作业1(LeetCode1)
- python3使用requests包抓取并保存网页源码
- Linux虚拟网络之tun(三)隔离网络下的Raw转发
- 452. Minimum Number of Arrows to Burst Balloons Java解法
- ImageLoader使用及源码解析
- RadioButton动态设置Margin
- java 如果文件目录不存在就创建再写文件的代码实例--针对“系统找不到指定的路径”问题。
- mybatis 在select语句中使用foreach语句报错
- 18 QT里的摄像头编程
- 矩阵最大值(解题报告)
- 文章标题