badvpn中tun2socks工具如何读取tun设备中的packet并将其通过socks5转发的呢? 我们知道在badvpn中使用到了LwIP, tun设备中的packet首先由LwIP处理,将TCP packet解析出来再进行转发?
- 关于badvpn的相关应用
请看这里:
- 关于LwIP
项目主页请看这里 :https://savannah.nongnu.org/projects/lwip/
这是它的相关介绍:
lwIP is a small independent implementation of the TCP/IP protocol suite that has been initially developed by Adam Dunkels and is now continued here.
The focus of the lwIP TCP/IP implementation is to reduce resource usage while still having a full scale TCP. This makes lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM.
Main features include:
– Protocols: IP, ICMP, UDP, TCP, IGMP, ARP, PPPoS, PPPoE
– DHCP client, DNS client, AutoIP/APIPA (Zeroconf), SNMP agent (private MIB support)
– APIs: specialized APIs for enhanced performance, optional Berkeley-alike socket API
– Extended features: IP forwarding over multiple network interfaces, TCP congestion control, RTT estimation and fast recovery/fast retransmit
– Addon applications: HTTP server, SNTP client, SMTP client, ping, NetBIOS nameserver
源代码可以从这里下载:https://savannah.nongnu.org/git/?group=lwip
- 使用的LwIP与upstream的差异
这里我们先确定一下badvpn的版本:
commit ffd16e27d0bd58fec068fa9271b33fe559efb5a5 Author: Ambroz Bizjak <ambrop7@gmail.com> Date: Sun Mar 12 12:02:02 2017 +0100 Fix bug UDP checksum calculation. Check for zero result should be done after not before inverting.
而最后一次修改LwIP的时间是:
commit cedb690976a130b6721a4956c652bacfffaaeaae Author: Ambroz Bizjak <ambrop7@gmail.com> Date: Sun Nov 16 17:13:25 2014 +0100 lwip: Fix undefined behavior.
可以看到lwip好长时间没有更新了。
从LwIP相关的log及lwip/CHANGELOG文件可以找到与upstream最接近的版本为:
commit 9809f1ff6600466da3f96fb304791201c54b34fc Author: Simon Goldschmidt <goldsimon@gmx.de> Date: Wed Apr 24 21:38:01 2013 +0200 Fixed bug #38586
通过diff命令我们可以看到badvpn修改了哪些代码:
diff -E -b -B -w -r badvpn/lwip/src/core/ipv4/ip4.c lwip/src/core/ipv4/ip4.c 476,481d475 < /* if we're pretending we are everyone for TCP, assume the packet is for source interface if it < isn't for a local address */ < if (netif == NULL && (inp->flags & NETIF_FLAG_PRETEND_TCP) && IPH_PROTO(iphdr) == IP_PROTO_TCP) { < netif = inp; < } < diff -E -b -B -w -r badvpn/lwip/src/core/ipv6/ip6.c lwip/src/core/ipv6/ip6.c 481,486d480 < /* if we're pretending we are everyone for TCP, assume the packet is for source interface if it < isn't for a local address */ < if (netif == NULL && (inp->flags & NETIF_FLAG_PRETEND_TCP) && IP6H_NEXTH(ip6hdr) == IP6_NEXTH_TCP) { < netif = inp; < } < diff -E -b -B -w -r badvpn/lwip/src/core/ipv6/nd6.c lwip/src/core/ipv6/nd6.c 624,627c624 < s8_t i; < #if LWIP_IPV6_AUTOCONFIG < s8_t j; < #endif --- > s8_t i, j; 1403d1399 < #if LWIP_IPV6_AUTOCONFIG 1405d1400 < #endif diff -E -b -B -w -r badvpn/lwip/src/core/netif.c lwip/src/core/netif.c 352,358d351 < int netif_is_named (struct netif *netif, const char name[3]) < { < u8_t num = name[2] - '0'; < < return (!memcmp(netif->name, name, 2) && netif->num == num); < } < 445,453d437 < void netif_set_pretend_tcp (struct netif *netif, u8_t pretend) < { < if (pretend) { < netif->flags |= NETIF_FLAG_PRETEND_TCP; < } else { < netif->flags &= ~NETIF_FLAG_PRETEND_TCP; < } < } < 754c738 < tcpip_callback((tcpip_callback_fn)netif_poll, netif); --- > tcpip_callback_with_block((tcpip_callback_fn)netif_poll, netif, 0); 861c845 < u8_t i, addr_index, min_len; --- > u8_t i, addr_index; 884d867 < min_len = netif->hwaddr_len < 8 ? netif->hwaddr_len : 8; 886c869 < for (i = 0; i < min_len; i++) { --- > for (i = 0; i < 8; i++) { diff -E -b -B -w -r badvpn/lwip/src/core/tcp.c lwip/src/core/tcp.c 212c212 < if (pcb->local_port != 0 || pcb->bound_to_netif) { --- > if (pcb->local_port != 0) { 487d486 < pcb->bound_to_netif = 0; 496,521d494 < < err_t < tcp_bind_to_netif(struct tcp_pcb *pcb, const char ifname[3]) < { < LWIP_ERROR("tcp_bind_if: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); < < /* Check if the interface is already in use */ < for (int i = 0; i < NUM_TCP_PCB_LISTS; i++) { < for(struct tcp_pcb *cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { < if (IP_PCB_IPVER_EQ(pcb, cpcb) && < cpcb->bound_to_netif && < !memcmp(cpcb->local_netif, ifname, sizeof(cpcb->local_netif))) { < return ERR_USE; < } < } < } < < pcb->bound_to_netif = 1; < ipX_addr_set_any(PCB_ISIPV6(pcb), &pcb->local_ip); < pcb->local_port = 0; < memcpy(pcb->local_netif, ifname, sizeof(pcb->local_netif)); < TCP_REG(&tcp_bound_pcbs, pcb); < LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind_to_netif: bind to interface %c%c%c\n", ifname[0], ifname[1], ifname[2])); < return ERR_OK; < } < 564c537 < if (ip_get_option(pcb, SOF_REUSEADDR) && !pcb->have_local_netif) { --- > if (ip_get_option(pcb, SOF_REUSEADDR)) { 584d556 < lpcb->bound_to_netif = pcb->bound_to_netif; 586d557 < memcpy(lpcb->local_netif, pcb->local_netif, sizeof(pcb->local_netif)); 598c569 < if (pcb->local_port != 0 || pcb->bound_to_netif) { --- > if (pcb->local_port != 0) { 754d724 < LWIP_ERROR("tcp_connect: cannot connect pcb bound to netif", !pcb->bound_to_netif, return ERR_VAL); 1569,1570c1539 < if ((!lpcb->bound_to_netif && !pcb->bound_to_netif && < (lpcb->local_port == pcb->local_port) && --- > if ((lpcb->local_port == pcb->local_port) && 1573,1575c1542 < ipX_addr_cmp(PCB_ISIPV6(lpcb), &pcb->local_ip, &lpcb->local_ip))) || < (lpcb->bound_to_netif && pcb->bound_to_netif && < !memcmp(lpcb->local_netif, pcb->local_netif, sizeof(pcb->local_netif)))) { --- > ipX_addr_cmp(PCB_ISIPV6(lpcb), &pcb->local_ip, &lpcb->local_ip))) { diff -E -b -B -w -r badvpn/lwip/src/core/tcp_in.c lwip/src/core/tcp_in.c 222,223d221 < struct tcp_pcb_listen *netif_pcb = NULL; < struct tcp_pcb *netif_pcb_prev = NULL; 225,231c223 < if (lpcb->bound_to_netif) { < if (IP_PCB_IPVER_INPUT_MATCH(lpcb) && netif_is_named(inp, lpcb->local_netif)) { < netif_pcb = lpcb; < netif_pcb_prev = prev; < } < } < else if (lpcb->local_port == tcphdr->dest) { --- > if (lpcb->local_port == tcphdr->dest) { 268,271d259 < if (lpcb == NULL && netif_pcb) { < lpcb = netif_pcb; < prev = netif_pcb_prev; < } 510,512c498 < npcb->bound_to_netif = pcb->bound_to_netif; < npcb->local_port = tcphdr->dest; < memcpy(npcb->local_netif, pcb->local_netif, sizeof(pcb->local_netif)); --- > npcb->local_port = pcb->local_port; diff -E -b -B -w -r badvpn/lwip/src/include/lwip/netif.h lwip/src/include/lwip/netif.h 100,102d99 < /** Whether to pretend that we are every host for TCP packets. < * Set by netif_set_pretend_tcp. */ < #define NETIF_FLAG_PRETEND_TCP 0x100U 241c238 < u16_t flags; --- > u8_t flags; 327,328d323 < int netif_is_named (struct netif *netif, const char name[3]); < 334d328 < void netif_set_pretend_tcp(struct netif *netif, u8_t pretend); diff -E -b -B -w -r badvpn/lwip/src/include/lwip/tcp.h lwip/src/include/lwip/tcp.h 166,168c166 < int bound_to_netif; \ < u16_t local_port; \ < char local_netif[3] --- > u16_t local_port 238c236 < u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ --- > u16_t snd_queuelen; /* Available buffer space for sending (in pbufs). */ 351d348 < err_t tcp_bind_to_netif (struct tcp_pcb *pcb, const char ifname[3]);
从这里我们可以看到badvpn修改了这些文件:
badvpn/lwip/src/core/ipv4/ip4.c badvpn/lwip/src/core/ipv6/ip6.c badvpn/lwip/src/core/ipv6/nd6.c badvpn/lwip/src/core/netif.c badvpn/lwip/src/core/tcp.c badvpn/lwip/src/core/tcp_in.c badvpn/lwip/src/core/tcp_out.c badvpn/lwip/src/include/lwip/netif.h badvpn/lwip/src/include/lwip/tcp.h
总的来说是为了获取TCP packet并对其进行处理。
- 关于TUN设备
文档:https://en.wikipedia.org/wiki/TUN/TAP
TUN (namely network TUNnel) simulates a network layer device and it operates with layer 3 packets like IP packets. TAP (namely network tap) simulates a link layer device and it operates with layer 2 packets like Ethernet frames. TUN is used with routing, while TAP is used for creating a network bridge.
Packets sent by an operating system via a TUN/TAP device are delivered to a user-space program which attaches itself to the device. A user-space program may also pass packets into a TUN/TAP device. In this case the TUN/TAP device delivers (or “injects”) these packets to the operating-system network stack thus emulating their reception from an external source.
- 关于TCP协议
看图,看原文
(图片来自https://en.wikipedia.org/wiki/Transmission_Control_Protocol)
- 工作原理
执行如下命令
badvpn-tun2socks --netif-ipaddr 10.0.0.1 --netif-netmask 255.255.255.0 \ --socks-server-addr 127.0.0.1:1080 \ --tunfd 66 --tunmtu 1500 --loglevel 5 --udpgw-remote-server-addr 192.168.1.6:8700
1. 通过lwip创建虚拟设备ho0
INFO(lwip): netif_set_ipaddr: netif address being changed INFO(lwip): netif: IP address of interface INFO(lwip): netif: netmask of interface INFO(lwip): netif: GW address of interface DEBUG(tun2socks): netif func init INFO(lwip): netif: added interface ho IP addr INFO(lwip): 10.0.0.1 INFO(lwip): netmask INFO(lwip): 255.255.255.0 INFO(lwip): gw INFO(lwip): 0.0.0.0 INFO(lwip): INFO(lwip): netif: setting default interface ho INFO(lwip): tcp_bind_to_netif: bind to interface ho0
2. 读取packet
00000000: 45 00 00 3c 5c c7 40 00 40 06 6e 6c 0a 00 00 02 E..<\.@.@.nl.... 00000010: 5d 2e 08 59 8a 60 01 bb fd de 46 95 00 00 00 00 ]..Y.`....F..... 00000020: a0 02 ff ff ed 96 00 00 02 04 05 b4 04 02 08 0a ................ 00000030: 00 00 1a 52 00 00 00 00 01 03 03 06 ...R........
3. 解析packet
INFO(lwip): ip_input: iphdr->dest 0x59082e5d netif->ip_addr 0x100000a (0x82e5d, 0xa, 0x59000000) INFO(lwip): ip_input: iphdr->dest 93.46.8.89 netif->ip_addr 10.0.0.1 mask 255.255.255.0 (93.46.8.0, 10.0.0.0, 0.0.0.89)
INFO(lwip): ip_input: INFO(lwip): IP header: INFO(lwip): +-------------------------------+ INFO(lwip): | 4 | 5 | 0x00 | 60 | (v, hl, tos, len) INFO(lwip): +-------------------------------+ INFO(lwip): | 23751 |010| 0 | (id, flags, offset) INFO(lwip): +-------------------------------+ INFO(lwip): | 64 | 6 | 0x6e6c | (ttl, proto, chksum) INFO(lwip): +-------------------------------+ INFO(lwip): | 10 | 0 | 0 | 2 | (src) INFO(lwip): +-------------------------------+ INFO(lwip): | 93 | 46 | 8 | 89 | (dest) INFO(lwip): +-------------------------------+ INFO(lwip): ip_input: p->len 60 p->tot_len 60 INFO(lwip): TCP header: INFO(lwip): +-------------------------------+ INFO(lwip): | 35424 | 443 | (src port, dest port) INFO(lwip): +-------------------------------+ INFO(lwip): | 4259202709 | (seq no) INFO(lwip): +-------------------------------+ INFO(lwip): | 0000000000 | (ack no) INFO(lwip): +-------------------------------+ INFO(lwip): | 10 | |000010| 65535 | (hdrlen, flags ( INFO(lwip): SYN INFO(lwip): INFO(lwip): ), win) INFO(lwip): +-------------------------------+ INFO(lwip): | 0xed96 | 0 | (chksum, urgp) INFO(lwip): +-------------------------------+ INFO(lwip): inet_chksum_pseudo(): checksumming pbuf 0xb6c98800 (has next 0x0) INFO(lwip): inet_chksum_pseudo(): pbuf chain lwip_chksum()=ffff INFO(lwip): tcp_input: packed for LISTENing connection. INFO(lwip): TCP connection request 35424 -> 443. INFO(lwip): tcp_parseopt: MSS INFO(lwip): tcp_parseopt: other INFO(lwip): tcp_parseopt: other INFO(lwip): tcp_parseopt: NOP INFO(lwip): tcp_parseopt: other INFO(lwip): tcp_enqueue_flags: queuelen: 0 INFO(lwip): tcp_enqueue_flags: queueing 6510:6511 (0x12) INFO(lwip): tcp_enqueue_flags: 1 (after enqueued) INFO(lwip): tcp_output: snd_wnd 65535, cwnd 1, wnd 1, effwnd 0, seq 6510, ack 6510 INFO(lwip): tcp_output: snd_wnd 65535, cwnd 1, wnd 1, effwnd 0, seq 6510, ack 6510, i 0 INFO(lwip): tcp_output_segment: rtseq 6510 INFO(lwip): tcp_output_segment: 6510:6510 INFO(lwip): inet_chksum_pseudo(): checksumming pbuf 0xb6ca2000 (has next 0x0) INFO(lwip): inet_chksum_pseudo(): pbuf chain lwip_chksum()=40d8
INFO(lwip): ip_output_if: ho0 INFO(lwip): IP header: INFO(lwip): +-------------------------------+ INFO(lwip): | 4 | 5 | 0x00 | 44 | (v, hl, tos, len) INFO(lwip): +-------------------------------+ INFO(lwip): | 0 |000| 0 | (id, flags, offset) INFO(lwip): +-------------------------------+ INFO(lwip): | 255 | 6 | 0x4c43 | (ttl, proto, chksum) INFO(lwip): +-------------------------------+ INFO(lwip): | 93 | 46 | 8 | 89 | (src) INFO(lwip): +-------------------------------+ INFO(lwip): | 10 | 0 | 0 | 2 | (dest) INFO(lwip): +-------------------------------+
4. 写入数据
INFO(lwip): netif->output() 00000000: 45 00 00 2c 00 00 00 00 ff 06 4c 43 5d 2e 08 59 E..,......LC]..Y 00000010: 0a 00 00 02 01 bb 8a 60 00 00 19 6e fd de 46 96 .......`...n..F. 00000020: 60 12 16 d0 27 bf 00 00 02 04 05 b4 `...'.......
还没看懂,待续。。。
- 实现一个简单的tun2socks
待续。。。
- 相关的参考文档
- https://savannah.nongnu.org/projects/lwip/
- https://github.com/ambrop72/badvpn
- https://en.wikipedia.org/wiki/Transmission_Control_Protocol
- https://en.wikipedia.org/wiki/TUN/TAP
你好,我正在开发一个android上的https 代理(http tunnel)看到你的blog 有这方面的文章,想从你这砍点经验值。 求线上联络方式=)
已私信
貌似我看不到私信 =。。=
看看现在有没有收到
小項目ChibiOS看看有興趣沒?
hello, 有問題請教,QQ:15777903
这种东西,用普通SOCKS5,还可以实现局部代理,不用路由表。
参考8u18.com有例程。