分类目录归档:未分类

安装Tailscale客户端

0. 安装key

curl -fsSL https://pkgs.tailscale.com/stable/debian/bullseye.noarmor.gpg |  tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/debian/bullseye.tailscale-keyring.list |  tee /etc/apt/sources.list.d/tailscale.list

或者
curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.noarmor.gpg |  tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.tailscale-keyring.list |  tee /etc/apt/sources.list.d/tailscale.list

1. 安装Tailscale

# apt update
# apt install tailscale

2. 注册并连接

tailscale up --login-server=http://headscale.softs.im:8080 --accept-routes=true --accept-dns=false

它会生成一个key并 通知healscale

https://headscale.softs.im/register/nodekey:1fd6a7cb0b68ce395465d2d5720c531d8c0fd7f2345f9ab71ee0b37463408024

在headscale机器上,进行确认

headscale -n softeam nodes register --key nodekey:1fd6a7cb0b68ce395465d2d5720c531d8c0fd7f2345f9ab71ee0b37463408024

确认后, 注册命令会自动成功, 因为它每秒都在向 tailscale进行查询

3. 断开

tailscale down

4. 注销

tailscale logout

5. 通过主机名 查到对方的IP

 tailscale ip  peer_hostname

如果不提供hostname, 就是查自己的IP

6. ping 对方结点

tailscale ping  hostname-or-ip

7.查看网络报告

tailscale netcheck

8. 查看连接状态

tailscale status
fd7a:115c:a1e0::1 voice                voiceteam    linux   -
fd7a:115c:a1e0::2 racknerd             voiceteam    linux   active; direct [2001:2002:2003:2004::9999]:41641, tx 9288 rx 7896

可以看出来, 到racknerd是通过IPV6直连的

Linux测试path mtu

ping   -c 2  -M do  -4    -s  1472      192.168.1.1
PING 192.168.1.1 (192.168.1.1) 1472(1500) bytes of data.
1480 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.680 ms
1480 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=1.15 ms

因为加上icmp的header长度为28, payload最多只能为1472, 因为ethernet的mtu是1500

ping -c 2 -M do -4 -s 1372 114.114.114.114
ping -c 2 -M do -4 -s 1372 218.104.111.122 (联通)

IPv6

ping   -c 2  -M do  -6    -s  1384      2408:8888::8
ping   -c 2  -M do  -6    -s  1384      www.qq.com

IPv4 header (20 bytes)
IPv6 header (40 bytes)

实际测试, IPV6路由设备比较新, 反而可以带更多数据

在阿里云上 连接 he.net

ping   -c 2  -M do  -4    -s  1472      he.net

ethernet 14
ipv4 20
ip 1480-1464 = 16
payload 1464

无线数据网络 4G LTE/5G NR MTU居然只有 1400

Some US based cellular networks require a lower than default MTU to be used on our router’s PPP interface.
If the MTU is left as the default value, the result will be that packets larger than the network maximum will be discarded. This shows up as web pages not displaying in the web browser when using our cellular router as a gateway to the internet.

Recommended values are:
AT&T 1420 bytes
Verizon 1428 bytes
Others 1430 bytes
(PPP interface default is 1500 bytes)

To ensure our routers work well on all carriers. set the PPP interface local and remote MRU to 1420.

Via CLI (telnet / SSH / ‘Execute a command’ in the GUI):
ppp 1 l_mru 1400
ppp 1 r_mru 1400
config 0 save
ppp 1 deact_rq

在VPS上测试google

 
ping   -c 2  -M do  -6    -s  1452      www.google.com
ping   -c 2  -M do  -4    -s  1472      www.google.com

恰好说明IPV6 头部 比 IPV4大20字节

电信 5G 对 电信5G, 也是 1452

ping -c 2 -M do -6 -s 1432 国外
ping -c 2 -M do -6 -s 1452 240e:d:1000:100::6

少的这20个字节,是 tb 😃

OpenGNB

OpenGNB 是一个开源的 P2P 去中心化的具有极致的内网穿透能力的软件自定义虚拟网络(Software Defined Virtual Network),可以让你把公司-家庭网络组成直接访问的局域网。

1. 极致的链路能力

内网穿透,无需公网IP,无限速影响,upnp,multi index,port detect,multi socket 等策略实现内网穿透
Discover in lan 自动发现局域网内其他节点建立 P2P 通信
Unified Forwarding 自动通过已经建立 P2P 通信的节点转发 IP 分组,多节点重传 IP 分组
Relay Forwarding 高度自定义中继路由,IP 分组发往下一个中继点前都会作加密处理
Standard Forwarding 用尽一切办法无法建立起 P2P 通信的节点可以通过位于公网 forward 节点中继 IP 分组

2. 数据安全
基于椭圆曲线数字签名实现可靠的身份验证
根据时间同步变更通信密钥
默认选项下对日志中的敏感信息进行隐藏

3. 多平台支持
GNB 用 C 语言开发,项目相关代码以开源方式发布, 编译时不需要引用第三方库文件,可以方便移植到当前流行的操作系统上,目前支持的操作系统及平台有 Linux_x86_64,Windows10_x86_64, macOS,FreeBSD_AMD64,OpenBSD_AMD64,树莓派,OpenWRT;大至服务器环境,桌面系统,小至仅有 32M 内存的OpenWRT路由器都能很好的运行 GNB 网络。


GNB节点间通过UDP协议传输数据,在一些网络环境下的路由器/防火墙会对UDP分组实施QOS策略,因此通过tcp链路转发GNB数据是不需要改动GNB通讯协议又可以提升GNB网络适应能力的一个办法。

gnb_udp_over_tcp是一个为 GNB 开发的通过 tcp 链路中转 UDP 分组转发的服务,也可以为其他基于 UDP 协议的服务中转数据。

tailscale

基于wireguard的mess vpn

headscale
https://github.com/juanfont/headscale

netmaker
https://github.com/gravitl/netmaker

innernet
https://github.com/tonarino/innernet

wesher
https://github.com/costela/wesher

tuic

https://github.com/EAimTY/tuic

Delicately-TUICed high-performance proxy built on top of the QUIC protocol

TUIC’s goal is to minimize the handshake latency as much as possible

用Rust编写的

nftables

由三个主要组件组成:内核实现、libnl netlink通信和nftables用户空间前端。 内核提供了一个netlink配置接口以及运行时规则集评估,libnl包含了与内核通信的基本函数,nftables前端是用户通过nft交互。

nftables 区分 命令行输入的临时规则 和 从文件加载或保存到文件的永久规则。
默认配置文件是/etc/nftables.conf,其中已经包含一个名为inet filter的简单ipv4/ipv6防火墙列表

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
	chain input {
		type filter hook input priority filter;
	}
	chain forward {
		type filter hook forward priority filter;
	}
	chain output {
		type filter hook output priority filter;
	}
}

默认是关闭的

systemctl status  nftables
○ nftables.service - nftables
     Loaded: loaded (/lib/systemd/system/nftables.service; disabled; preset: enabled)
     Active: inactive (dead)

启用它
systemctl enable nftables
systemctl start nftables

iptables的缺点

iptables框架在内核态知道的太多,以至于产生了大量的代码冗余。
iptables的rule结构设计不合理。

检查 命令行 规则集

 nft list ruleset

列出所有的表

nft list tables

Phantun

https://www.v2ex.com/t/802949
https://github.com/dndx/phantun
作者: dndx

将 UDP 流量伪装成 TCP 流量的主流工具是 udp2raw

Phantun 的目标不是为了替代 udp2raw,从一开始 Phantun 就希望设计足够的简单高效,所以 udp2raw 支持的 ICMP 隧道,加密,防止重放等等功能 Phantun 都选择不实现。

Phantun 假设 UDP 协议本身已经解决了这些问题,所以整个转发过程就是简单的明文换头加上一些必要的 TCP 状态控制信息。对于我日常使用的 WireGuard 来说,Phantun 这种设计是足够安全的,因为 WireGuard 的协议已经更好的实现了这些安全功能。

Phantun 使用 TUN 接口来收发 3 层数据包,udp2raw 使用 Raw Socket + BFP 过滤器。个人感觉基于 TUN 的实现要稍微的优雅一点,而且跨平台移植也要更容易。

Phantun 的 TCP 连接是按需创建的,只启动 Client 不会主动去连接服务器,需要第一个数据包到达了后才会按需创建。每个 UDP 流都有自己独立的 TCP 连接。这一点跟 udp2raw 很不一样,udp2raw 所有的 UDP 连接共用一个 TCP 连接。这样做的坏处就是 udp2raw 需要额外的头部信息来区分连接,更加增加了头部的开销。跟纯 UDP 比较,Phantun 每个数据包的额外头部开销是 12 byte,udp2raw 根据我的测试达到了 44 bytes 。

https://icloudnative.io/posts/wireguard-over-tcp-using-phantun/

https://icloudnative.io/posts/custom-derp-servers/

0. 编译
… 过程省略 .. 参考 rust 相关帖子

1. 在服务器上配置,运行

设置转发
iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination 192.168.201.2

运行

RUST_LOG=info  ./server --local 4567 --remote 127.0.0.1:1234
 INFO  server > Remote address is: 127.0.0.1:1234
 INFO  server > 1 cores available
 INFO  server > Created TUN device tun0
 INFO  server > Listening on 4567

创建tun

tun0
    inet 192.168.201.1 peer 192.168.201.2/32 scope global tun0

让第三方的 UDP 服务,监听在 127.0.0.1的1234 端口

2. 客户端配置,运行

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

运行
RUST_LOG=info ./client --local 127.0.0.1:1234 --remote server_ip:4567

监听在本地的 127.0.0.1的1234端口

第3方客户端, 直接连接到 127.0.0.1:1234 就相当于 连接到 远程的UDP服务

建立一个tun0

tun0: 
    inet 192.168.200.1 peer 192.168.200.2/32 scope global tun0

phantun监听在本地的 127.0.0.1:1234 UDP, 同时创建了一个 tun0设备, tun0设备的本端ip为 192.168.200.1, 对端ip为
192.168.200.2
来自于 123 udp端口的的 数据, 都被以 192.168.200.2的IP, 连接到 server_ip:4567 用tcp发送出去

但这个tcp连接, 又被 iptable改写了 源地址, 从 192.168.200.2 改成 了 客户端自己的主机地址

3. 测试程序

#!/usr/bin/env python 

 
import socket 
import sys 
import argparse 
from time     import sleep
 
host = '127.0.0.1' 
payload_size = 2048 
 
def echo_server(peer,  bind_port, to_port): 
    sock = socket.socket(socket.AF_INET,  socket.SOCK_DGRAM) 
    server_address = (host, bind_port) 
    print ("Starting up echo server on %s port %s" % server_address) 
    sock.bind(server_address) 
    sock.settimeout(5.0)
    
    index = 1
 
    while True: 
        try:
            print ("Waiting to receive message  from client") 
            data, address = sock.recvfrom(payload_size) 
         
            print ("received %s bytes from %s" % (len(data), address)) 
            print ("Data: %s" %data) 
         
            if data: 
                #data = b'###...' + data + b'...###'
                data = b'### %i' % index
                sent = sock.sendto(data, address) 
                print ("sent %s bytes back to %s" % (sent, address))
                index = index + 1
                sleep(1)
        except socket.timeout:
            #addr = (peer, to_port)
            #data = b'count %i' % index
            #sent = sock.sendto(data, addr) 
            #print ("sent %s bytes hello to %s" % (sent, addr)) 
            index = index + 1
 
 
if __name__ == '__main__': 
    parser = argparse.ArgumentParser(description='Socket Server Example') 
    parser.add_argument('--host', action="store", dest="host", type=str, required=True)     
    parser.add_argument('--bind', action="store", dest="bind_port", type=int, required=True) 
    parser.add_argument('--to', action="store", dest="to_port", type=int, required=True) 
        
    given_args = parser.parse_args()
    peer = given_args.host    
    local_port = given_args.bind_port
    remote_port = given_args.to_port    
 
    
    echo_server(peer, local_port, remote_port) 

在服务端运行

python3 ttt_echo_server.py  --host  cliet_peer_ip  --bind  1234  --to 9999

监听在udp的1234端口

在客户端运行

python3 ttt_echo_server.py --host 127.0.0.1 --bind 9999 --to 1234

它会往 本地 127.0.0.1 的1234 udp端口发送数据, 从而fake tcp转发给 服务器

INFO fake_tcp > Sent SYN to server
INFO fake_tcp > Connection to 111.222.333.444:4567 established

4. 关于MTU
WireGuard MTU = Interface MTU – IPv4 header (20 bytes) – TCP header (20 bytes) – WireGuard overhead (32 bytes)
IPv4: 1500 – 20 – 20 – 32 = 1428
phantun作者介绍的,应该这么算, 但我实际设置为 1480 也是通的

he tb ipv6后

ping -c 2  -M do  -4    -s  1364    10.0.0.1

ipv4 直连 (MTU居然只有1400)

ping   -c 2  -M do  -4    -s  1372  server_public_ip
1372(1400)

ipv4 udp wireguard直连

ping -c 2  -M do  -4    -s  1452    10.0.0.1

1452(1480)

ipv4 tcp wireguard

 ping -c 2  -M do  -4    -s  1396    10.0.0.1

实际浪费56个字节

IPV4 20
IPCP 16

Usually the MTU of most networks is 1500. So the MTU of IPv6 tunnel should be 1480 by removing the 20 bytes IPv4 header. To set a proper MTU that neither cause IPv6 packet be truncated nor be too small for IPv6, You’d better find the IPv4 MTU from you to your tunnel relay server by your self and set the IPv6 MTU by minus 20 bytes.

5. 几个坑点
(1) 在服务器上,如果运行的是

./server --local 4567 --remote 127.0.0.1:1234

也就是转发给 127.0.0.1:1234 这个 udp监听端口, 必须严格监听在 127.0.0.1:1234
监听在 0.0.0.0:1234 是不能正常工作的
(2)客户端, iptable命令的出口 网卡名字必须正确指定

iptables  -t nat -A POSTROUTING -o br0  -j MASQUERADE

如果用了网桥, 必须设置为网桥的名字

cjdns

https://github.com/cjdelisle/cjdns

UDP协议

编译需要rust和nodejs环境

cd /opt
git clone https://github.com/cjdelisle/cjdns.git
cd cjdns
./do
ln -s /opt/cjdns/cjdroute /usr/bin
(umask 077 && ./cjdroute --genconf > /etc/cjdroute.conf)
cp contrib/systemd/*.service /etc/systemd/system/
systemctl enable cjdns
systemctl start cjdns

yggdrasil

https://github.com/yggdrasil-network/public-peers
https://github.com/yggdrasil-network/yggdrasil-android
https://github.com/yggdrasil-network/crispa-android