2017/05/06

【关于题外话在最后】
写作本文主要基于两点,首先是因为我前段时间写了几篇关于XXN的新解,收到了很多的邮件反馈,我也思考了很多,另一个方面是因为很多人问我怎么用QQ,P2P搭建一个IP层的Tunnel,我的回答是“我也不知道”。我确实不知道,根本就没有试过,只是有个这样那样的想法…我主要是没有动力和能力去Hack这些非Linux上的东西…所以说,我写这篇文章,用UNIX的方法 “将多个小工具结合起来” 实现我的那些没有实现的想法,抛砖引玉一下。

声明:
本文没有技术含量,甚至不会有什么代码,本文只是一些Linux bash和netcat的使用技巧之堆砌,但我觉得只有这种是理解Everything over App的最好方式,虽然我没有能力将TAP对接到QQ上,但我有能力将其对接到netcat以及ssh上,而netcat,ssh和QQ并没有什么本质的区别,结论是,只要你能找一个通信软件,Tunnel便可以嫁接于其上。

在这里插入图片描述

Tunnel的种类
一般而言,传统的Tunnel都是用新的IP报文来运输原始IP报文的,这种新的IP报文往往封装一个新的四层头。但是也有用TCP,UDP来运输原始IP报文的,典型的例子就是OpenXXN,BadXXN等。
事实上,你可以用任何的报文来运输原始IP报文,在上一篇文章《从一个简单的聊天程序SimpleChat看XXX技术》中,我提到你可以用QQ,P2P协议来运输IP报文,并且给出了一个应景的设想。本文将通过简单的实例来实现一下这种设想。

发展阶段
像类似PPPoE,L2TP什么的,提出了一个很好的框架和概念,说明IP over XXX的可行性,然后OpenXXN掀开了一次Revolution,说明IP可以over UDP,并且和SSL/TLS进行了深度结合,小众的BadXXN应该是另一次Revolution的,但是作者好像没有把握住机会,和OpenXXN不同的是,BadXXN旨在提供灵活且独立的点对点组网能力。

在研究了BadXXN之后,我自己写了一个简单的Demo,即SimpleXXN
https://github.com/marywangran/overlay

其实,BadXXN的思路很简单,这个和我们平时的聊天软件的思路完全一致,不同的是聊天软件运输的是我们键盘输入的消息,而BadXXN运输的则是从TAP网卡中读取的IP报文。借着这个思路,我觉得任何的可以进行网络通信的软件都可以运输IP报文,只需要将程序的输入和输出重定向到TAP网卡的输入和输出即可,这非常简单。

准备工作
如果说TAP网卡在文件系统中以一个文件的形式存在,那么事情会非常简单,比如tap0网卡在文件系统中有一个字符设备文件/dev/tap0,那么以scp为例,我便可以通过以下的命令来运输通过tap0传输的IP报文或者以太帧:

scp /dev/tap0 root@192.168.44.129:/dev/tap0
1
然而自打Linux 2.6.x(8<x<32)起,内核便不再提供这种机制了。至少在2.6.8的内核中,有一个ethertap的模块,它提供了我上述所说的“理想方法”,你只需要以下的命令便可以构建一个tap0文件:

modprobe ethertap
ifconfig tap0 10.10.10.10/24 up
mknod /dev/tap0 c 36 16

1
2
3
4
可是到了2.6.32内核,ethertap模块没有了,只剩下了tun模块,使用tun模块,无法直接建立tap0的设备文件,必须通过ioctl来显式设置它:

modprobe tun
tunctl -u root -t tap0

注意,tun模块让你无法通过命令构建一个可以直接读写的tap0设备文件,你必须写一个程序显式执行open/ioctl对,然后操作其文件描述符进行读写。


1
2
3
4
这意味着我不得不写一个程序了,而这令不会编程的我感到悲哀!我把该文件命名为tunio.c,如下所示:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <fcntl.h>

struct frame {
unsigned int len;
char data[2000];
};

// 为了便于重定向操作,我在本程序中只使用了3个文件描述符:TAP网卡字符设备,标准输入,标准输出
int main(int argc, char **argv)
{
int fd = -1;
struct ifreq ifr;
size_t len;
char buf[2004];
struct frame frm;
int i;
fd_set rd_set;

    if( (fd = open("/dev/net/tun", O_RDWR)) < 0) {exit(-1);}memset(&ifr, 0, sizeof(ifr));ifr.ifr_flags |= IFF_NO_PI;ifr.ifr_flags |= IFF_TAP;snprintf(ifr.ifr_name, IFNAMSIZ, "%s", "tap0");ioctl(fd, TUNSETIFF, (void *)&ifr);while(1) {int nfds;int j;FD_ZERO(&rd_set);FD_SET(0, &rd_set);FD_SET(fd, &rd_set);char *tmp;nfds = select(1024, &rd_set, NULL, NULL, NULL);for (j = 0;j < nfds; j++) {// 如果标准输入有动静的话if(FD_ISSET(0, &rd_set)) {unsigned int dlen;// 从标准输入中读取数据长度len = read(0, &dlen, sizeof(unsigned int));// 按照指示的长度读取原始IP报文或者数据帧len = read(0, frm.data, dlen);// 将IP报文或者数据帧写入TAP设备len = write(fd, frm.data, len);}// 如果虚拟网卡字符设备有动静if(FD_ISSET(fd, &rd_set)) {// 从网卡读取IP报文或者以太帧len = read(fd, buf, sizeof(buf));// 为了对端可以区分数据边界,加入了长度头frm.len = len;memcpy(frm.data, buf, len);tmp = (char *)&frm;// 将加入长度头的原始数据输出到标准输出for (i = 0; i < len+sizeof(unsigned int); i++) {printf("%c", tmp[i]);}}// 刷新输出fflush(NULL);}}return 0;

}
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
将以上的代码编译成tunio即可:

gcc tunio.c -o tunio
1
然后就可以用这个tunio和其它的既有程序进行基于UNIX哲学的组合从而构建出一个看起来像那么回事的Tunnel了。

在继续之前,我不得不说一下不能继续使用ethertap的原因。

一个好好的ethertap为什么就下课了呢?其实很大的原因在于ethertap所依赖的Netlink机制被重构了。在2.4版本以及2.6的早期版本的内核中,Netlink消息是通过字符设备进行读写的,然而后来Netlink便不再采用字符设备了,而是采用socket API进行读写了,而socket并没有导出文件到文件系统这也是众所周知,socket仅仅导出文件到进程。然而这跟ethertap下课有关吗?有的!

ethertap之所以可以导出文件到文件系统,就是使用的Netlink字符设备,你看看上述的mknod命令,其major设备号36就是Netlink的major设备号:

#define NETLINK_MAJOR 36
1
在init_netlink中:

if (register_chrdev(NETLINK_MAJOR,“netlink”, &netlink_fops)) {

1
2
在ethertap模块代码中,你看不到任何关于字符设备的逻辑,事实上ethertap的字符设备文件的读写逻辑已经被Netlink接管,这个从hard_xmit以及netif_rx这两个协议栈的读写接口中便可获知,它们都是直接与Netlink接口。

好了,现在Netlink不再采用字符设备的方式了,改由API调用的方式控制了,那么ethertap便面临两个选择,一个是也跟着采用API的方式进行控制,而这个与tun模块功能重复,另一个选择是为ethertap单独注册一个字符设备类型,或者将其注册到misc设备,但这样会使字符设备集合越来越臃肿…再者说了,不还有tun的吗?编个程序封装一下读写控制逻辑有那么难吗?所以说,只能下课了…

其实,虽然ethertap好用,但其实现方式是有问题的,试想如果大家都为每一个功能注册一个Netlink号码,或者注册一种字符设备,那么几乎可以肯定,这种横向的平坦拓展方式总有一天会让Netlink或者字符设备管理机制不堪重负…之前的ioctl问题就是一个例子。

下面开始真正有意思的东西。

使用netcat实现一个简单的Demo
小用一下这个被誉为“瑞士军刀”的小巧nc,我来展示一下IP报文是如何通过nc构建的连接运输到另一个任意节点的。

我把tunio的标准输出重定向到netcat的标准输入,然后把netcat的标准输出重定向到tunio的标准输入,事情就成了,这让整个事情变成了一个环:
在这里插入图片描述
是不是很简单呢?

那么怎么实现呢?虽然逻辑上上图已经足够简单,但是实现上还是需要一个pipe作为过渡的,因此我们先在两台机器上分别创建一个pipe:

mkfifo /tmp/tmp_fifo
1
接下来的玩法完全取决于你对netcat的熟悉程度,本文不讲netcat,只说Tunnel,所以直接给出命令:

机器1:

cat /tmp/tmp_fifo | ./tunio 2>&1 | nc -l 1567 >/tmp/tmp_fifo
ifconfig tap0 10.10.10.10/24 up

机器2:

cat /tmp/tmp_fifo | ./tunio 2>&1 | nc 192.168.44.100 1567 >/tmp/tmp_fifo
ifconfig tap0 10.10.10.20/24 up
1
2
3
4
5
6
然后你来试试在机器2上去ping机器1的tap0的地址,绝对通了。这下,我们在物理网络的TCP连接上成功构建了一个承载以太帧的Ethernet over TCP的Overlay,显然这还远远不够,我们来抓包看看。在机器2上执行:

curl 10.10.10.10
1
同时在机器1上抓包:

tcpdump -i any tcp port 1567 -n -w overlay1.pcap
1
打开这个overlay1.pcap,我们可见:
在这里插入图片描述

好吧,虽然很完美的完成了隧道封装,然而没有实现加密…某种意义上,这并不是XXN,具体为啥我在这里多说无益。技术归技术,我们现在的目标是实现加密传输。这简直太简单了。

在继续展示加密隧道之前,我必须来点题外话为netcat做点推广。在前几篇文章中,我提到了QQ,P2P,甚至差点连飞鸽传书都扯上,但这些对Linux用户来讲,都是被鄙视的。在Linux上难道不是netcat这把瑞士军刀最靠谱吗?如果两人都使用Linux,最轻便的聊天工具就是netcat,根本不用装别的什么乱七八糟的东西。

实现一个加密隧道:使用ncat
当然,按照UNIX的传统方法,使用netcat和一个加密解密的命令加上输入输出重定向,就能在上节例子的基础上实现加密隧道,比如可以nc…|mcrypt…,然而我没有成功!所以我不得不使用别的方案。

幸亏有一个好用的ncat可以使用,我直接就用了。其实还有一个cryptcat可用,但我没有用成功,如果用成功的,希望可以告诉我。我本人对bash重定向的掌握一直都是半吊子水平,所以用起来当然没有玩Netfilter,XXN这般得心应手。决定使用ncat,命令如下:

机器1:

cat /tmp/tmp_fifo | ./tunio 2>&1 | ncat -vnl 333 --ssl >/tmp/tmp_fifo
#【以下特意给出屏幕输出,以显示正在初始化加密套件】
ifconfig tap0 10.10.10.10/24 up
1
2
3
4
在这里插入图片描述

机器2:

cat /tmp/tmp_fifo | ./tunio 2>&1 |ncat -nv 192.168.44.100 333 --ssl >/tmp/tmp_fifo
#【以下特意给出屏幕输出,以显示正在初始化加密套件】
ifconfig tap0 10.10.10.20/24 up
1
2
3
4
5
在这里插入图片描述

同上面的netcat明文实例一样,依然在机器2上执行curl,在机器1上抓包,得到如下结果:

在这里插入图片描述
我不可能去解释这些密文是什么个含义,总之,这就是一条加密的隧道,构建成功了。至于说加密强度如何,不属于本文的范畴。

实现一个加密隧道:使用ssh
其实一开始我是希望使用scp来做tap0字符设备文件的传输的,中间我采用了一个fifo pipe来过渡,但是没有成功,貌似scp的源文件必须是Regular file才可以,不能是pipe。后来我决定放弃,进而寻找别的方案。毕竟,搞清楚scp并不是我的目的,其实我完全可以修改scp的源码使之适应pipe传输的,但是这样做毫无意义。

放弃了scp后,我转向了直接使用ssh来执行远程命令,ssh执行远程命令要比scp更加通用,而不仅仅只是一个“文件传输”机制。废了大力之后,也算是小成功了,仍然是上述的机制,我的命令如下:

机器1:

mkfifo /tmp/tmp_fifo
./tunio </tmp/tmp_fifo |ssh root@192.168.44.129 “cat >/tmp/tmp_fifo”
ifconfig tap0 10.10.10.10/24

机器2:

mkfifo /tmp/tmp_fifo
./tunio </tmp/tmp_fifo |ssh root@192.168.44.100 “cat >/tmp/tmp_fifo”
ifconfig tap0 10.10.10.20/24
1
2
3
4
5
6
7
8
这个更加对称,比使用netcat/ncat的方式更加对称,更加优雅,但是效率去不咋地。抓包我就不给出了,大家自己品鉴吧。

本质
总的来讲,扯以上这些,我就是想说明一个观点,构建一个加密的隧道其实非常简单,方法更是多种多样,如果有人问你什么是XXN,你给他展示一下用Linux2.4内核ethertap模块+netcat+mcrypt或者快速手写一个tunio,然后配合ncat或者配合ssh构建一条加密隧道,那么你就算彻底理解了XXN的本质,如果你能快速让QQ和tunio这类程序对接,那你就是百折不扣的高手!当然,我达不到这样的水平,我只是指路人,我只是鼓手。当然,如果你真的拿netcat,ncat,ssh和tunio,ethertap这类对接了,很多学院派,科班生会觉得你这根本不是XXN,因为在他们眼里,XXN就是L2TP,PPTP,…,MPLS之流,你这自己搭建的,根本就什么都不是…其实我觉得这种学院派才是什么都不懂。

XXN在概念上满足两点即可,第一就是V(虚拟),第二是P(专用),这两点分别用Overlay和加解密技术完全可以完美表达。至于是L2TP,…等,它们只是成熟的标准之作罢了,但完全没有做到大道至简。

感谢老一辈程序员使我可以写就本文
这部分本想放在文章最前面的,但是怕喧宾夺主,所以移到了最后。

说实话,本文根本没有任何技术含量,但是绝对可以引发人们的思考。在我2006年刚刚参加工作的时候,我什么都不懂。但我跟一帮上世纪90年代以及21世纪前5年的程序员一起学到了很多的东西,比如用鼠标线上网,用串口联网,…他们说以前的时候,以太网卡和网线是稀缺的,反而PS/2,RS232是常见的,人们普遍都是使用物理单机,然后依靠软盘,刻录光盘,后来的U盘作为介质来传输数据,这就好比我之前说的用卡车运数据时一样的。

如果说我在一块没有接线网卡(假设它没有接线依然可以运行)上抓到了一个数据帧,然后把这个帧放到了一个U盘里,将U盘通过卡车,轮船运送到了外国,在外国有人将这个数据帧注入到了一个没有接线的网卡里,那么在协议栈看来,这个主机就跟从网线上收到了这个数据帧是一样的…所以说,网线只是个介质。

在2010年的时候,我第一次知道了TAP网卡这种东西,发现IP数据报文还可以通过一个字符设备读到用户态应用程序,进而被加密后通过socket传输出去,我觉得这太妙了!这难道不是跟用串口联网一样的道理吗?用串口和用socket唯一的区别就是,前者将原始IP数据写进了串口,而后者将原始IP数据写入socket,在应用程序看来,这没什么不同,都是写入了一个文件而已。之所以可以这么理解,得益于UNIX的两个传统,一个是IO的文件本质,一切皆文件,读写文件即可,第二个是分层的协议栈模型,这使得Overlay成为了可能!

好吧,我来总结一下,其实没什么好总结的,几乎都一样:

串口联网:IP字符设备fd<—>APP<—>串口字符设备
OpenXXN:IP字符设备fd(tun/tap)<—>OpenXXN<—>socket
本文范例:IP字符设备fd(tun/tap)<—>netcat/ncat/ssh<—>socket
大家都一样,最终大家都回归到了最开始的状态!中间的IPSec之流实乃昙花一现也。

鉴于此,我将我本文的简单返璞归真的方法自诩为另一种革命,承接于IPXXc,OpenXXN,BadXXN。如果你能玩的得心应手,就可以出神入化,随心所欲了,你的XXN数据将不再建立在协议的基础上,它甚至没有自己的协议,完全传输裸数据,因此也就没有任何的可以识别的Pattern。

不管是用USB联网,还是用串口联网,或者用任意APP上网,我们都要记住,这完全得益于一切皆文件以及分层协议栈的馈赠啊。你和想建立XXN连接的主机之间,无非有两种连接方式,第一种就是物理直连,即通过网线,串口线,USB线,无线等连接起来的,另一种就是逻辑连接,即虽然不是物理介质之间连接的,但却是可以通过TCP/IP协议栈连接在一起的,比如用一对socket就能互相通信。不管以上哪一类,XXN连接在乎的是只要能和对端保证TCP/IP可达即可。

推荐一本书,《全球城市史》,今天周六刚刚看完,虽然篇幅比较短小,但确实很好看,从这本书里思考,你可以看到我本文一样的观点。古代大家自给自足,都待在家里做工,后来大家集中式地先后走向工厂,走向写字楼,走向园区,如今随着交通和通讯技术越来越发达,大家再次回到了家里工作,同样都是在家工作,但层次却完全不同,可能在未来几十年,我们会再次回到男耕女织的生活,但是和古代的男耕女织却完全不同,古代的男耕女织是无组织的个体行为,而未来的男耕女织却是一个整体组织中的一环…以前,没有网线,网卡匮乏,大家用串口,USB,鼠标线等做Overlay,如今网络资源过剩,大家用TCP/IP做Overlay…网络技术在更高的层次上实现了回归。

想象一下大型机工作站时代,大家通过哑终端接入这些超级计算机,自己的终端可能离计算机很远,终端仅仅提供输入输出功能,根本没有计算功能,慢慢的计算资源逐渐移到了终端,这便开启了个人计算机时代,接下来,随着计算需求的增加,计算资源有一次集中了,这次不叫大型机了,这次叫云端,同样的,云计算也是在更高的层次实现了回归。

原文链接:https://blog.csdn.net/dog250/article/details/107641404?utm_medium=distribute.pc_feed.none-task-blog-personrec_tag-2.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-personrec_tag-2.nonecase&request_id=5f21e6108c9fb674c67219c4

用netcat,SSH构建IP层Tunnel(转载)相关推荐

  1. 用netcat,SSH构建IP层Tunnel

    2017/05/06 [关于题外话在最后] 写作本文主要基于两点,首先是因为我前段时间写了几篇关于XXN的新解,收到了很多的邮件反馈,我也思考了很多,另一个方面是因为很多人问我怎么用QQ,P2P搭建一 ...

  2. LWIP之IP层实现(转载)

    原文地址:http://bluefish.blog.51cto.com/214870/158417 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...

  3. 《TCP/IP详解卷1:协议》——第2章:链路层(转载)

    1.引言 从图1-4可以看出,在TCP/IP协议族中,链路层主要有三个目的: (1)为IP模块发送和接收IP数据报: (2)为ARP模块发送ARP请求和接收ARP应答. (3)为RARP发送RARP请 ...

  4. IP 层收发报文简要剖析4--ip 报文发送

    无论是从本地输出的数据还是转发的数据报文,经过路由后都要输出到网络设备,而输出到网络设备的接口就是dst_output(output)函数 路由的时候,dst_output函数设置为ip_output ...

  5. linux 内核网络协议栈--数据从接收到IP层(二)

    此处主要讲的是从数据来到,中断到最终数据包被处理的过程. 首先来介绍一下IO端口访问问题,内核提供了这样一组函数处理: /kernel/io.c中 inb( ).inw( ).inl( )函数 分别从 ...

  6. auto drop ssh failed ip address

    #/bin/bash #auto drop ssh failed ip address #author by efoni 2018.7 SEC_FILE=/var/log/secure #如下为截取s ...

  7. IP 层收发报文简要剖析1-ip报文的输入

    ip层数据包处理场景如下: 网络层处理数据包文时需要和路由表以及邻居系统打交道.输入数据时,提供输入接口给链路层调用,并调用传输层的输入接口将数据输入到传输层. 在输出数据时,提供输出接口给传输层,并 ...

  8. 一文讲解Linux 内核网络协议栈-数据从接收到ip层

    [推荐阅读] 一文了解Linux上TCP的几个内核参数调优 一文剖析Linux内核中内存管理 分析linux启动内核源码 此处主要讲的是从数据来到,中断到最终数据包被处理的过程. 0:首先来介绍一下I ...

  9. 利用ISCSI存储技术构建IP存储网络(概念篇)

    一.iSCSI的概念iSCSI是一种在Internet协议上,特别是以太网上进行数据块传输的标准,它是一种基于IP Storage理论的新型存储技术,该技术是将存储行业广泛应用的SCSI接口技术与IP ...

最新文章

  1. linux mysql 主从 1130_Linux Mysql 1130错误解决
  2. mysql 关联 update_关于SQL UPDATE关联更新
  3. @AutoWired和@Resource注解异同分析
  4. dubbo protocol port 消费者端_springboot整合dubbo设置全局唯一ID进行日志追踪
  5. 贪心 - 按要求补齐数组
  6. python QTreeWidgetItem下面有几个子tree_python-nlp ch1笔记:nlp的基础应用、高级应用、python优势、nltk环境搭建...
  7. mysql 连接工具
  8. tar打包/解包用法
  9. 不懂开发的运维,未来该如何发展?
  10. sql 安装程序文件_【病毒文件分析】MedusaLocker勒索病毒,小心全网被加密
  11. oracle 存过 的语法,oracle 存储过程的基本语法_oracle
  12. 用HTML5制作简单的个人简历
  13. 在线图片转文字怎么转?这两种方法简单又实用!
  14. 什么是flex布局,它的常用属性有哪些
  15. 网站实时监控系统的设计与实现
  16. Matlab绘制图像(plot函数)
  17. java面试题(记录与分享)二
  18. 唠唠 U盘格式 (Normal:FAT32 NTFS exFAT)以及U盘格式化选什么格式好???
  19. 六、系统架构 - 高可用架构设计
  20. 计算机运行慢 卡是什么原因是什么原因,电脑很卡是什么原因?电脑卡的原因有哪些...

热门文章

  1. vue实现无限下级修改名称(递归)
  2. 办理劳务资质要多少钱?关键看办理方法
  3. Java学习_从常用类到多线程引入
  4. 交互式python解释器_Python交互式解释器及用法
  5. 湖北科技职业学院计算机专业,戴文华 - 湖北科技学院 - 计算机科学与技术学院...
  6. python编译器安装教程
  7. 一篇bootstrap的教程 -- 来自runoob
  8. android apk获取root权限执行相应的操作 demo调试
  9. 【原创】大三体会篇(中)
  10. 前端面试之--网络相关