ICKelin

Results 17 issues of ICKelin

接触过VPN相关技术的基本都会接触过虚拟网卡,tun,tap等字眼,因为大部分vpn都或多或少使用有类似技术。本文会对tun/tap设备的基本原理进行说明,并且对其如何应用在vpn上进行了分析,最后提供一个简单的tun的vpn的实现代码。 ### TUN/TAP设备的基本原理 首先需要明确一点,tun和tap是两种类型的虚拟设备,其一大区别是从tun设备读取数据,你将能够拿到三层包,从tap网卡获取数据,你将能拿到二层包。 在了解虚拟网卡之前,应该先简单了解下真实网卡是如何进行工作的。 首先,网卡介于物理网络和内核协议栈之间,接受协议栈外出的数据并将数据往物理网络发出,同时,也接受外部数据并交付给内核协议栈进行处理。(在这里先将内核协议栈当成一个整体,一个黑盒来看待。) 了解物理网卡所处的位置以及网络数据包的流动之后,再看看虚拟网卡有什么不一样的地方。 从最直观的使用来看,用户是可以直接读写虚拟网卡的,也就是说,从内核协议栈发出的数据在选定以虚拟网卡发出之后,数据将会被用户层程序直接读取,这点与物理网卡不一样,物理网卡直接就往外发。虚拟网卡告知用户程序数据可读。 在写方面,用户进程往虚拟网卡写数据会直接从网卡写出去 一图胜千言: ![image](https://user-images.githubusercontent.com/9639491/37972873-dd866320-320b-11e8-9ab6-0cdcc0ee718e.png) ### TUN/TAP与VPN 了解了TUN与TAB的基本原理之后,可以明确的知道,用户层通过虚拟网卡具备有读写二层,三层数据包的能力,这种读写与原始套接字还不一样,原始套套接字做的事旁路拷贝,这个是直接截取数据包到用户层,用户层自己处理。 有了这类技术底子之后,再看看vpn,很多人一提到vpn就想到翻墙,vpn并不等于翻墙,vpn的一个目的是为不同地区模拟出一个局域网环境,让A地区的员工能够像访问局域网一样访问位于总部B的服务器或者其他比如打印机,这是vpn。 一图胜千言: ![image](https://user-images.githubusercontent.com/9639491/38034332-a4b513ec-32d4-11e8-9fde-3183781e5083.png) ping经过内核协议栈,路由选择从虚拟网卡发出 虚拟网卡的另外一端,也就是用户进程,将这一ping包读取出来 将ping的payload通过真实网卡发出,经过一系列的传输,到达目的主机, 目的主机收到数据包之后,将其写入虚拟网卡。 Ping reply返回类似,上图的左右两端是等价的,能够收发数据包。 为了方便说明这一原理,编写一个简单的基于tun设备的vpn——gtun gtun客户端: ```golang package main import (...

现在很多人有时间都希望写一些自己的代码,把自己的一些想法给实现一下,在实现自身想法的过程当中,可能会忽略一些基础组件的重要性,我之前也是非常不重视基础组件,然后一箩筐代码写下来,写完了,后面再来开发一些基础组件,改动还是挺大的。 在开发notr的过程当中,前期专注软件的实现,经过一波又一波的优化,软件功能基本满意之后,又想着如何去把软件介绍给别人使用,依然还记得第一个愿意使用的用户,第一个付费的用户,当时特别的兴奋,虽然在亏钱。。 软件使用的人慢慢多了之后,那么就跟之前不一样了,没人用的时候,软件挂了之后去重启就好了,产生不了任何价值,自然也就没有太多的压力。现在有不少用户了,而且是付费的用户,那么就需要对用户负责,系统肯定不能挂。我需要了解整个系统的状态。并且一旦系统出现异常时及时通知我进行恢复,这时候我开始考虑花心思去构建一个监控相关的基础服务,以达到以下目的: - 故障通知 - 监控应用状态 - 监控应用内部数据 对于实现这些目的,我的要求只有一个,那就是快速搞好,最好一天之内能够解决掉,因为这个不是我的重点,数据丢失无关紧要。 这里面比较关注的是故障通知,通知要比较及时,采用邮件的方式肯定是不行的,短信又太贵,最终我选择了一个比较罕见的方式,使用微信公众号,推送模版消息,这种方式能够很好的解决我的问题,一方面是免费的,另一方面一天有最多十万条,所以次数肯定是满足了的,有过公众号开发的可能知道模版推送需要资质,个人不能使用,正是因为个人使用,所以没有太深究,既然都不深究了,那么**公众号直接拿测试公众号即可。** 应用状态监控,应用内部数据监控这种有太多的解决方案了,我选择了一种比较熟悉的方式,监控显示用的是grafana,grafana数据源用的influxdb。把数据往influxdb里面插即可,influxdb提供了http接口,对大部分开发人员而言问题都不大。接下来就是将应用数据指标上报的influxdb当中,这里需要开发量,有两种方式: - 开发一个基础库,基础库嵌入到应用程序当中,应用程序直接写入数据到influxdb - 开发一个agent和一个基础库,基础库还是嵌入到应用程序当中,但是数据是上报到agent,由agent写到influxdb。 最后选择了第二种方式,第一种方式虽然只有一个基础库,但是后续如果我需要调整grafana的数据源,不用influxdb了,那所有应用都需要进行适配,采用第二种方式只有agent需要适配。而且评估了下,开发周期相差也不大。 最终整体的监控就采用这么个过程: ![image](https://user-images.githubusercontent.com/9639491/76870482-b80ce700-68a4-11ea-854c-3c2e111890cc.png) 开发任务有两个,其一是开发agent,agent通过http调用influxdb,其二是开发api,让应用程序能够简单的使用,并且不能阻塞应用程序的运行,agent与api之间的通信采用的是grpc客户端流模式,整个思路应该算是很多公司都在采用的一种方式,只是个别地方可能不太一样,整体类似。 把上面的任务分解之后接下来就是一步一步把整个流程执行一遍,我分为以下几个步骤进行: - 先用安装好influxdb和grafana并做好配置 - 开发agent程序和基础库,并提供接口给其他服务接入 完成以上两个个步骤之后,整个系统的监控基本上可以有效的运行了。 ## 安装和配置influxdb,grafana 这个相对比较容易,到官网去下载运行就行。 [grafana](https://grafana.com/)...

在我开发的项目[notr内网穿透](https://www.notr.tech)当中引入DNS来解决动态配置*.notr.tech的A记录的问题,针对用户test,每次客户端连上来之后都要设置test.notr.tech的A记录为当前连接的服务器。目前DNS版本还非常简单,已经开源成[notrns](https://github.com/ICKelin/notrns)项目。但是这个项目还有几个问题: - 数据存储在boltdb当中,只能单点用 - 如果流量比较大,需要部署多个dns节点,数据同步问题比较麻烦 - 性能有待测试,能工作,但是工作的极限还不知道 通过github了解到[CoreDNS](https://github.com/coredns/coredns)和[etcd](https://github.com/etcd-io/etcd)两个项目,就琢磨着用CoreDNS代替notrns来做动态域名解析,使用etcd来做存储。 ![](https://user-gold-cdn.xitu.io/2019/6/21/16b78387ec8f1aa7?w=1592&h=1090&f=png&s=100906) 按照这种流程进行,迁移方便,开发量也少,扩展起来也容易。 ## 测试 1. 启动etcd 2. 启动coredns CoreFile: ``` notr.tech { etcd { path /skydns endpoint http://localhost:2379 upstream } log }...

如果按照创建管理员用户作为上线时间的话,[Notr内网穿透](http://www.notr.tech)已经上线将近一年了,第一个用户是在2018年七月份,期间做过一次大的方案修改,最大的一次方案修改是春节放假期间把VPN的方式放弃,采用了新的思路去解决这个问题。终于软件整体趋于稳定,用户也很少报bug,也推出了license模式。近期由于推广力度加大,用户数量也在稳步上升,今天算是达到了三位数。在这一年期间碰到过很多非常友好也很有意思的用户,这将是Notr软件给我带来的另外的价值,这对目前对我而言比软件本身挣不挣钱更加重要,可以很肯定对说,软件肯定是不挣钱的。 在此记录下一些印象比较深刻的用户。 ### 第一个用户 首个用户是2018年七月注册的,当时是在一个群里面试着告诉大家我在开发一个软件,看谁有兴趣用,然后当时就有个群友联系了我,说想用下,我说windows要安装虚拟网卡,装完然后就用,对方想用来穿透windows远程桌面服务的,我说你可以穿透tcp 3389端口就行了。然后第一次用户使用以失败告终,主要是没考虑windows防火墙的问题,然后代码里面手动把VPN的地址段都放行,最后才勉强可以。 ### 来自粉丝圈的用户 我是很喜欢杨超越的,主要是太搞笑了,然后之前杨超越粉丝圈组织了一个超越杯编程大赛,当时就想,哎,像这种远程协作的,要调试接口的时候就用得到啊,如果做小程序或者微信公众号的时候,也用得到啊。然后就在微博和知乎发贴,当时说的是免费提供服务,直到比赛结束。谁知道编程大赛没给我带来多少流量,但是有个哥们却跟我说想一起做,然后想了下觉得可以,有兴趣就行,然后就开始建了github私有项目。不过最终这个哥们还是没有一起做下去,主要是时间问题还有本身也不太了解这方面知识。 ### 爽快又不爽快的用户 前两天跟朋友吃饭,说起了最近有个用户买了一年license,很爽快,然后聊着聊着就回想这个用户注册的用户名是什么,然后想起来对方居然是当初我看着用了一个月的tcp服务,试用期过了就只用http,而且用的还是旧版本,当时就觉得,我去,本来就有需求的,一个月花点钱买个又怎样呢。当时没有验证注册用户的邮箱,对方填了个假邮箱,我联系不上,最后我换了个新版本,我把老版本一刀切,所有老版本的程序都在后台返回了版本过旧,目的是希望对方能够进入官网加群。后来对方确实加了群,在license功能推出来之后,立马买了一年的license。。 ### 很难搞的用户 没有企业资质在中国做不了支付,然后我就在软件登录之后,链接到淘宝商品,让对方去淘宝下单,但是也有用户是在淘宝搜一个一个翻找到我挂在淘宝上的软件的。其中有一个印象最深,对方找了我两次,前后相隔一个月,第一次的时候对方问我限速多少,我说3m,对方说是300多k的那种吗,我说3mbps,然后对方立马说再见,过一会又回来说,我的是ubuntu喔,可以吗,我说可以,校内网喔,可以上网吗?可以,那就没问题。校内网。。我知道校内网。。然后就没有然后了。再过将近一个月,对方又通过淘宝找到了我,问我限速多少,我说3mbps,行吧。然后叫我教他怎么用,我说注册,下载,运行。你到第三步的时候跟我说我告诉你有哪些配置,然后对方不注册,直接下载运行,跑了三个小时,我说你可以注册,注册成功之后会给你一个固定的域名。然后对方又不了了之了。 ### 海外用户 这类用户我也觉得很神奇,我从来没在海外的站点发布过。对方说是在知乎看到我的回答然后找到我的,之前用的ngrok太卡了,完全不能用,就想试试看能不能行。当时香港的云服务器已经关闭了,对方用我的客户端也会被调度到深圳的节点,对方不是很满意,延时两百多毫秒,有点卡,我说你等下,我开个香港的节点给你用下试试,然后延时瞬间降了两百毫秒,跟本地使用ssh一样。但是还不行,我说你现在之所以能够连上香港的,是因为我现在调度策略很简单,就根据客户端数量均衡,香港节点现在刚启动,所以很自然就选到了香港。我这边需要加上根据客户端ip进行调度的功能,然后第二天上线之后对方觉得可以接受。 总的来说,我对这个软件根本不报任何挣钱的期望,开发这个也不是为了挣钱,当用户量较小的时候,本来成本就不高,当用户量大的时候,收取的软件费用足以支撑服务器成本,当时通过这个软件能够让我有一个服务意识,然后也接触了不少用户。

为提高英语,花两个小时写了个爬取voa上的英文新闻,主要用了goquery这个库,没其他的了,关键是能够解决我自身的需求。如果您很关注性能,或者非常纠结与代码的美观,那么这段代码可能会被喷,anyway,我认为能够用最快的方式解决我问题的就ok了,毕竟我写这个的目的是解决实际的问题。 项目部署在我的树莓派上,使用[Notr](https://www.notr.tech)进行内网穿透,可以通过[voa](http://voavoa.notr.tech) 或者[voa](http://voavoa.dahuizong.com) 进行访问。 ``` package main import ( "fmt" "io/ioutil" "log" "os" "strconv" "strings" "time" "github.com/gin-gonic/gin" "github.com/PuerkitoBio/goquery" ) var ( defaultSite = "http://www.51voa.com" defaultEntry = "http://www.51voa.com/Technology_Report_1.html" defaultDir = "./news"...

先mark一下。 一直有个想法,想把[notr](http://www.notr.tech)这个软件再打磨得更好一点,当前一个反馈得比较多的问题是windows版本需要安装tap驱动,而且各个平台都需要管理员权限,如果这两个问题不解决,别说用户觉得不爽了,我本身就像是束缚住了手脚,万一哪天想不开想给她加上界面,也不是那么容易。 当前要解决下面两个问题 - 去掉虚拟网卡 - 支持组网,当前没有组网功能,但是在当前基础之上,想要做到组网其实是特别简单的。所以调整完之后,我也希望能够很好都适配组网功能。 很多vpn方案,像OpenVPN,都会用到虚拟网卡,做的是二层和三层转发,要去掉虚拟网卡,必须需要去掉二层和三层转发,要支持组网功能,以三层组网为例,就必须需要要有IP地址的概念。所以就设想了下: 可以给每个客户端编址,server维护编址表,**针对网络内部而言,只是一个逻辑地址,标识客户端而已,但是这一过程对用户是透明的**,任何客户端,或者在server上的程序,都能够访问得了这一逻辑地址,通过server的作为入口访问客户端,这是内网穿透,通过客户端A经过服务器访问客户端B,这是组网。这里面有一个细节需要考究,就是怎么让另一客户端或者server的数据走到目的客户端,这里说的是数据,也就是应用层数据,不包含IP头和TCP/UDP/ICMP头的。另外一个项目[inject_conntrack](https://github.com/ICKelin/inject_conntrack)或许能够派上用场 用一个图可以表示如下: ![image](https://user-images.githubusercontent.com/9639491/51428993-f416ce80-1c44-11e9-825c-a95674a7839b.png) 就notr这个软件开发当前开发而言也是存在一些平台问题,windows用tap网卡,linux/mac OS用的是tun网卡。代码本身也多了很多平台判断的逻辑,所以现在回想起来当初这么快下手去开发,也不知道是好事还是坏事,都有吧。 花了点时间验证下,发现这个思路做内网穿透是没有问题的,贴点代码,仅仅是验证,为了简化,部分是硬编码进去的: 客户端: 客户端硬编码了代理到127.0.0:8000这个地址,可以从server传递过来的。 ``` package main import ( "flag" "fmt" "io" "net" "sync" "github.com/xtaci/smux" ) func main()...

最近看到一段用c实现的channel,感觉挺小巧精妙的,就好好研究了下。 包含两个基本操作:1、往channel发送数据;2、从channel中读取数据 本质上是用一段内存来实现一个环形队列。用两个游标来指向队头和队尾。每次要发送时,往队尾加数据,要读取时,从队头游标获取数据,当内存块不足时进行扩容,扩容机制采用的是原来内存块*2的方式。针对并发操作,用锁来保证同一时刻环形队列只有一个线程操作。 下面是具体代码,代码量很少。 channel.h: 定义基本数据结构以及接口 ``` #ifndef _CHANNEL_H_ #define _CHANNEL_H_ #include "pv.h" typedef struct { int count; // allocate count int used; // used count int cursor; // current...

首先打广告,[内网穿透Notr](https://www.notr.tech),网站部分功能仍在开发,如果您也有兴趣参与Notr的开发,请给我留言。 在完成大部分[gtun](https://github.com/ICKelin/gtun) 的开发之后,已经能够解决将家里网络与公司网络组建成虚拟局域网,面临一个问题,我需要在两端同时gtun客户端方能连接公司的网络,于是就想到了内网穿透,基于gtun可以非常方便的进行内网穿透。在gtun当中也有部分内网穿透的功能,但是还不够,或者说我不认为将内网穿透加入gtun让gtun变得庞大无比是一件正确之举,于是我在gtun基础之上构建一个内网穿透的项目。gtun作为底层基础设施。 当时思考了下,应该具备以下功能: - 首先,地位应该是一个产品而不是一个开源项目,所以给用户使用的时候一定要考虑小白的情况,所以不需要众多的配置,只需要让用户知道,我本地起了什么端口,我只要告诉你我起了什么端口,你帮我让我能够通过公网访问就OK,所以Notr的客户端非常简洁,没有任何配置,只需要指定本地端口即可 - 其次,应该支持多种协议,HTTP,HTTPS,TCP,UDP - 最后,用户最终拿到的应该是域名而不是IP地址,如果是IP地址可能会经常变动,但是域名不会 于是开始了Notr的思考与实现。最初版本Notr针对HTTP和HTTPS是需要指定端口号的,朋友反馈基本上两个问题用得不舒服 - 端口号随机的,而且每次都不一样。产生这个的原因,是自身程序是不关注应用层协议的,只关注TCP层,而且我会都会监听一个端口来服务这一代理协议 - 其次,HTTPS安全连接的问题 于是用HTTP和HTTPS用Nginx反向代理代替,每次新生成一个Nginx配置文件,proxy_pass指定为用户的虚拟ip地址与端口即可。 这种方式实现将会特别简洁,而且会http可以使用默认的80端口,https可以使用默认的443端口,用户不需要记住端口号,仅仅需要记住域名。 Notr的运行截图如图所示: 对小白用户非常得友好。没有任何配置。目前支持多个windows,linux以及mac三个平台,不过windows需要安装tap-windows驱动,更多信息可在[notr](http://www.notr.tech)上了解,可执行文件可在[下载中心](http://www.notr.tech:8000)进行下载 详细处理流程: ![image](https://user-images.githubusercontent.com/9639491/43032258-4e3dcd72-8ce5-11e8-9844-4be23d69aed3.png)

网络层非常复杂,想通过这篇文章完全了解网络层是不太现实的,本文只是描述网络层的解决的一些问题,以及它具体是怎么解决的描述清楚。 ** 网络层解决的一个重要问题是如何将数据包送到目的地。** 网络层的互联通过路由器进行,路由器接收下级网络的数据,并转发到上一级(如果需要的话),这个属于路由转发,路由转发解决将数据包转发出去,但是在做路由转发之前,需要确定转发到哪个地址,只就需要路由器内部的路由表,如果目的地址在当前网络下,那就不需要转发给下一跳,否则获取到下一跳地址然后转发给下一跳,这里面又会引出另外两个问题,第一,怎么判定是否属于同一个网络,第二,路由表怎么生成,生成的依据是什么,这里面可能又需要涉及生成路由表的路由算法。每个路由器都需要做路由表匹配以及转发到下一跳的过程,但是路由算法并不需要每个路由器都运行,上述过程可以概括为以下流程。 ![image](https://user-images.githubusercontent.com/9639491/43363179-5185d41e-9331-11e8-9a10-e4294cceb923.png) 所以要实现路由器的转发功能,需要解决几个问题: - 如何确定是否属于同一个网络 - 如何生成路由表 - 如何匹配路由表 - 如何转发给下一跳 判定两个地址是否属于同一个网络 =================== 如何生成路由表——路由算法 =================== 路由匹配 =================== 路由转发 ===================