mirror of
				https://github.com/bjdgyc/anylink.git
				synced 2025-10-31 08:29:33 +08:00 
			
		
		
		
	
							
								
								
									
										103
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								README.md
									
									
									
									
									
								
							| @@ -87,6 +87,58 @@ sudo ./anylink --conf="conf/server.toml" | ||||
|  | ||||
| [conf/server.toml](server/conf/server.toml) | ||||
|  | ||||
|  | ||||
| ## Setting | ||||
|  | ||||
| 网络模式选择,需要配置 `link_mode` 参数,如 `link_mode="tun"`,`link_mode="tap"` 两种参数。 不同的参数需要对服务器做相应的设置。 | ||||
|  | ||||
| 建议优先选择tun模式,因客户端传输的是IP层数据,无须进行数据转换。 tap模式是在用户态做的链路层到IP层的数据互相转换,性能会有所下降。 如果需要在虚拟机内开启tap模式,请确认虚拟机的网卡开启混杂模式。 | ||||
|  | ||||
| ### tun设置 | ||||
|  | ||||
| 1. 开启服务器转发 | ||||
|  | ||||
|  ```shell | ||||
|  # flie: /etc/sysctl.conf | ||||
|  net.ipv4.ip_forward = 1 | ||||
|  | ||||
|  #执行如下命令 | ||||
|  sysctl -w net.ipv4.ip_forward=1 | ||||
|  ``` | ||||
|  | ||||
| 2. 设置nat转发规则 | ||||
|  | ||||
| ```shell | ||||
| # eth0为服务器内网网卡 | ||||
| iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE | ||||
| ``` | ||||
|  | ||||
| 3. 使用AnyConnect客户端连接即可 | ||||
|  | ||||
| ### tap设置 | ||||
|  | ||||
| 1. 创建桥接网卡 | ||||
|  | ||||
| ``` | ||||
| 注意 server.toml 的ip参数,需要与 bridge-init.sh 的配置参数一致 | ||||
| ``` | ||||
|  | ||||
| 2. 修改 bridge-init.sh 内的参数 | ||||
|  | ||||
| ``` | ||||
| eth="eth0" | ||||
| eth_ip="192.168.1.4" | ||||
| eth_netmask="255.255.255.0" | ||||
| eth_broadcast="192.168.1.255" | ||||
| eth_gateway="192.168.1.1" | ||||
| ``` | ||||
|  | ||||
| 3. 执行 bridge-init.sh 文件 | ||||
|  | ||||
| ``` | ||||
| sh bridge-init.sh | ||||
| ``` | ||||
|  | ||||
| ## Systemd | ||||
|  | ||||
| 添加 systemd脚本 | ||||
| @@ -155,57 +207,6 @@ systemd 脚本放入: | ||||
|    docker build -t anylink . | ||||
|    ``` | ||||
|  | ||||
| ## Setting | ||||
|  | ||||
| 网络模式选择,需要配置 `link_mode` 参数,如 `link_mode="tun"`,`link_mode="tap"` 两种参数。 不同的参数需要对服务器做相应的设置。 | ||||
|  | ||||
| 建议优先选择tun模式,因客户端传输的是IP层数据,无须进行数据转换。 tap模式是在用户态做的链路层到IP层的数据互相转换,性能会有所下降。 如果需要在虚拟机内开启tap模式,请确认虚拟机的网卡开启混杂模式。 | ||||
|  | ||||
| ### tun设置 | ||||
|  | ||||
| 1. 开启服务器转发 | ||||
|  | ||||
|  ```shell | ||||
|  # flie: /etc/sysctl.conf | ||||
|  net.ipv4.ip_forward = 1 | ||||
|  | ||||
|  #执行如下命令 | ||||
|  sysctl -w net.ipv4.ip_forward=1 | ||||
|  ``` | ||||
|  | ||||
| 2. 设置nat转发规则 | ||||
|  | ||||
| ```shell | ||||
| # eth0为服务器内网网卡 | ||||
| iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE | ||||
| ``` | ||||
|  | ||||
| 3. 使用AnyConnect客户端连接即可 | ||||
|  | ||||
| ### tap设置 | ||||
|  | ||||
| 1. 创建桥接网卡 | ||||
|  | ||||
| ``` | ||||
| 注意 server.toml 的ip参数,需要与 bridge-init.sh 的配置参数一致 | ||||
| ``` | ||||
|  | ||||
| 2. 修改 bridge-init.sh 内的参数 | ||||
|  | ||||
| ``` | ||||
| eth="eth0" | ||||
| eth_ip="192.168.1.4" | ||||
| eth_netmask="255.255.255.0" | ||||
| eth_broadcast="192.168.1.255" | ||||
| eth_gateway="192.168.1.1" | ||||
| ``` | ||||
|  | ||||
| 3. 执行 bridge-init.sh 文件 | ||||
|  | ||||
| ``` | ||||
| sh bridge-init.sh | ||||
| ``` | ||||
|  | ||||
| ## 常见问题 | ||||
|  | ||||
| 请前往 [问题地址](question.md) 查看具体信息 | ||||
|   | ||||
| @@ -2,5 +2,5 @@ package base | ||||
|  | ||||
| const ( | ||||
| 	APP_NAME = "AnyLink" | ||||
| 	APP_VER  = "0.2.1" | ||||
| 	APP_VER  = "0.3.1" | ||||
| ) | ||||
|   | ||||
| @@ -33,6 +33,7 @@ type ServerConfig struct { | ||||
| 	// LinkAddr      string `json:"link_addr"` | ||||
| 	ServerAddr     string `json:"server_addr"` | ||||
| 	ServerDTLSAddr string `json:"server_dtls_addr"` | ||||
| 	ServerDTLS     bool   `json:"server_dtls"` | ||||
| 	AdminAddr      string `json:"admin_addr"` | ||||
| 	ProxyProtocol  bool   `json:"proxy_protocol"` | ||||
| 	DbFile         string `json:"db_file"` | ||||
|   | ||||
| @@ -16,8 +16,9 @@ type config struct { | ||||
| } | ||||
|  | ||||
| var configs = []config{ | ||||
| 	{Typ: cfgStr, Name: "server_addr", Usage: "前台服务监听地址", ValStr: ":443"}, | ||||
| 	{Typ: cfgStr, Name: "server_dtls_addr", Usage: "前台DTLS监听地址", ValStr: ":4433"}, | ||||
| 	{Typ: cfgStr, Name: "server_addr", Usage: "服务监听地址", ValStr: ":443"}, | ||||
| 	{Typ: cfgBool, Name: "server_dtls", Usage: "开启DTLS", ValBool: false}, | ||||
| 	{Typ: cfgStr, Name: "server_dtls_addr", Usage: "DTLS监听地址", ValStr: ":4433"}, | ||||
| 	{Typ: cfgStr, Name: "admin_addr", Usage: "后台服务监听地址", ValStr: ":8800"}, | ||||
| 	{Typ: cfgBool, Name: "proxy_protocol", Usage: "TCP代理协议", ValBool: false}, | ||||
| 	{Typ: cfgStr, Name: "db_file", Usage: "数据库地址", ValStr: "./data.db"}, | ||||
|   | ||||
| @@ -25,8 +25,10 @@ admin_pass = "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke" | ||||
| jwt_secret = "iLmspvOiz*%ovfcs*wersdf#heR8pNU4XxBm&mW$aPCjSRMbYH#&" | ||||
|  | ||||
|  | ||||
| #前台服务监听地址 | ||||
| #服务监听地址 | ||||
| server_addr = ":443" | ||||
| #开启 DTLS, 默认关闭 | ||||
| server_dtls = false | ||||
| server_dtls_addr = ":4433" | ||||
| #后台服务监听地址 | ||||
| admin_addr = ":8800" | ||||
|   | ||||
| @@ -21,6 +21,10 @@ import ( | ||||
| // 最后,感谢 github.com/pion/dtls 对golang生态做出的贡献 | ||||
|  | ||||
| func startDtls() { | ||||
| 	if !base.Cfg.ServerDTLS { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	certificate, err := selfsign.GenerateSelfSigned() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
|   | ||||
| @@ -33,7 +33,8 @@ func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 			base.Error("SetDeadline: ", err) | ||||
| 			return | ||||
| 		} | ||||
| 		hdata := make([]byte, BufferSize) | ||||
| 		// hdata := make([]byte, BufferSize) | ||||
| 		hdata := getByteFull() | ||||
| 		n, err = conn.Read(hdata) | ||||
| 		if err != nil { | ||||
| 			base.Error("read hdata: ", err) | ||||
| @@ -65,8 +66,9 @@ func LinkCstp(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 			if payloadIn(cSess, sessdata.LTypeIPData, 0x00, hdata[8:8+dataLen]) { | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		putByte(hdata) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -78,9 +80,9 @@ func cstpWrite(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 	}() | ||||
|  | ||||
| 	var ( | ||||
| 		err     error | ||||
| 		n       int | ||||
| 		header  []byte | ||||
| 		err error | ||||
| 		n   int | ||||
| 		// header  []byte | ||||
| 		payload *sessdata.Payload | ||||
| 	) | ||||
|  | ||||
| @@ -95,7 +97,9 @@ func cstpWrite(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		header = []byte{'S', 'T', 'F', 0x01, 0x00, 0x00, payload.PType, 0x00} | ||||
| 		h := []byte{'S', 'T', 'F', 0x01, 0x00, 0x00, payload.PType, 0x00} | ||||
| 		header := getByteZero() | ||||
| 		header = append(header, h...) | ||||
| 		if payload.PType == 0x00 { // data | ||||
| 			binary.BigEndian.PutUint16(header[4:6], uint16(len(payload.Data))) | ||||
| 			header = append(header, payload.Data...) | ||||
| @@ -106,6 +110,9 @@ func cstpWrite(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		putByte(header) | ||||
| 		putPayload(payload) | ||||
|  | ||||
| 		// 限流设置 | ||||
| 		err = cSess.RateLimit(n, false) | ||||
| 		if err != nil { | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 	base.Debug("LinkDtls connect", cSess.IpAddr, conn.RemoteAddr()) | ||||
| 	base.Debug("LinkDtls connect ip:", cSess.IpAddr, "udp-rip:", conn.RemoteAddr()) | ||||
| 	dSess := cSess.NewDtlsConn() | ||||
| 	if dSess == nil { | ||||
| 		// 创建失败,直接关闭链接 | ||||
| @@ -35,7 +35,9 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 			base.Error("SetDeadline: ", err) | ||||
| 			return | ||||
| 		} | ||||
| 		hdata := make([]byte, BufferSize) | ||||
|  | ||||
| 		// hdata := make([]byte, BufferSize) | ||||
| 		hdata := getByteFull() | ||||
| 		n, err := conn.Read(hdata) | ||||
| 		if err != nil { | ||||
| 			base.Error("read hdata: ", err) | ||||
| @@ -51,9 +53,9 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 		switch hdata[0] { | ||||
| 		case 0x07: // KEEPALIVE | ||||
| 			// do nothing | ||||
| 			base.Debug("recv keepalive", cSess.IpAddr) | ||||
| 			// base.Debug("recv keepalive", cSess.IpAddr) | ||||
| 		case 0x05: // DISCONNECT | ||||
| 			base.Debug("DISCONNECT", cSess.IpAddr) | ||||
| 			base.Debug("DISCONNECT DTLS", cSess.IpAddr) | ||||
| 			return | ||||
| 		case 0x03: // DPD-REQ | ||||
| 			// base.Debug("recv DPD-REQ", cSess.IpAddr) | ||||
| @@ -67,6 +69,8 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		putByte(hdata) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -78,7 +82,7 @@ func dtlsWrite(conn net.Conn, dSess *sessdata.DtlsSession, cSess *sessdata.ConnS | ||||
| 	}() | ||||
|  | ||||
| 	var ( | ||||
| 		header  []byte | ||||
| 		// header  []byte | ||||
| 		payload *sessdata.Payload | ||||
| 	) | ||||
|  | ||||
| @@ -94,14 +98,21 @@ func dtlsWrite(conn net.Conn, dSess *sessdata.DtlsSession, cSess *sessdata.ConnS | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		header = []byte{payload.PType} | ||||
| 		header = append(header, payload.Data...) | ||||
| 		// header = []byte{payload.PType} | ||||
| 		header := getByteZero() | ||||
| 		header = append(header, payload.PType) | ||||
| 		if payload.PType == 0x00 { // data | ||||
| 			header = append(header, payload.Data...) | ||||
| 		} | ||||
| 		n, err := conn.Write(header) | ||||
| 		if err != nil { | ||||
| 			base.Error("write err", err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		putByte(header) | ||||
| 		putPayload(payload) | ||||
|  | ||||
| 		// 限流设置 | ||||
| 		err = cSess.RateLimit(n, false) | ||||
| 		if err != nil { | ||||
|   | ||||
| @@ -89,6 +89,7 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) { | ||||
| 	var ( | ||||
| 		err     error | ||||
| 		payload *sessdata.Payload | ||||
| 		frame   ethernet.Frame | ||||
| 	) | ||||
|  | ||||
| 	for { | ||||
| @@ -98,12 +99,14 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		var frame ethernet.Frame | ||||
| 		// var frame ethernet.Frame | ||||
| 		frame = getByteFull() | ||||
| 		switch payload.LType { | ||||
| 		default: | ||||
| 			// log.Println(payload) | ||||
| 		case sessdata.LTypeEthernet: | ||||
| 			frame = payload.Data | ||||
| 			copy(frame, payload.Data) | ||||
| 			frame = frame[:len(payload.Data)] | ||||
| 		case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据 | ||||
| 			data := payload.Data | ||||
|  | ||||
| @@ -148,6 +151,9 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) { | ||||
| 			base.Error("tap Write err", err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		putByte(frame) | ||||
| 		putPayload(payload) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -158,14 +164,16 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) { | ||||
| 	}() | ||||
|  | ||||
| 	var ( | ||||
| 		err error | ||||
| 		n   int | ||||
| 		buf []byte | ||||
| 		err   error | ||||
| 		n     int | ||||
| 		buf   []byte | ||||
| 		frame ethernet.Frame | ||||
| 	) | ||||
|  | ||||
| 	for { | ||||
| 		var frame ethernet.Frame | ||||
| 		frame.Resize(BufferSize) | ||||
| 		// var frame ethernet.Frame | ||||
| 		// frame.Resize(BufferSize) | ||||
| 		frame = getByteFull() | ||||
| 		n, err = ifce.Read(frame) | ||||
| 		if err != nil { | ||||
| 			base.Error("tap Read err", n, err) | ||||
| @@ -237,5 +245,7 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) { | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		putByte(frame) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -84,6 +84,8 @@ func tunWrite(ifce *water.Interface, cSess *sessdata.ConnSession) { | ||||
| 			base.Error("tun Write err", err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		putPayload(payload) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -98,15 +100,15 @@ func tunRead(ifce *water.Interface, cSess *sessdata.ConnSession) { | ||||
| 	) | ||||
|  | ||||
| 	for { | ||||
| 		data := make([]byte, BufferSize) | ||||
| 		// data := make([]byte, BufferSize) | ||||
| 		data := getByteFull() | ||||
| 		n, err = ifce.Read(data) | ||||
| 		if err != nil { | ||||
| 			base.Error("tun Read err", n, err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		data = data[:n] | ||||
|  | ||||
| 		// data = data[:n] | ||||
| 		// ip_src := waterutil.IPv4Source(data) | ||||
| 		// ip_dst := waterutil.IPv4Destination(data) | ||||
| 		// ip_port := waterutil.IPv4DestinationPort(data) | ||||
| @@ -114,9 +116,10 @@ func tunRead(ifce *water.Interface, cSess *sessdata.ConnSession) { | ||||
| 		// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default) | ||||
| 		// fmt.Println("read:", packet) | ||||
|  | ||||
| 		if payloadOut(cSess, sessdata.LTypeIPData, 0x00, data) { | ||||
| 		if payloadOut(cSess, sessdata.LTypeIPData, 0x00, data[:n]) { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		putByte(data) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -70,7 +70,7 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) { | ||||
| 	} | ||||
| 	cSess.CstpDpd = cstpDpd | ||||
|  | ||||
| 	dtlsPort := "" | ||||
| 	dtlsPort := "4433" | ||||
| 	if strings.Contains(base.Cfg.ServerDTLSAddr, ":") { | ||||
| 		ss := strings.Split(base.Cfg.ServerDTLSAddr, ":") | ||||
| 		dtlsPort = ss[1] | ||||
|   | ||||
| @@ -7,13 +7,12 @@ import ( | ||||
| ) | ||||
|  | ||||
| func payloadIn(cSess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool { | ||||
| 	payload := &sessdata.Payload{ | ||||
| 		LType: lType, | ||||
| 		PType: pType, | ||||
| 		Data:  data, | ||||
| 	} | ||||
| 	pl := getPayload() | ||||
| 	pl.LType = lType | ||||
| 	pl.PType = pType | ||||
| 	pl.Data = append(pl.Data, data...) | ||||
|  | ||||
| 	return payloadInData(cSess, payload) | ||||
| 	return payloadInData(cSess, pl) | ||||
| } | ||||
|  | ||||
| func payloadInData(cSess *sessdata.ConnSession, payload *sessdata.Payload) bool { | ||||
| @@ -44,16 +43,15 @@ func payloadOut(cSess *sessdata.ConnSession, lType sessdata.LType, pType byte, d | ||||
| } | ||||
|  | ||||
| func payloadOutCstp(cSess *sessdata.ConnSession, lType sessdata.LType, pType byte, data []byte) bool { | ||||
| 	payload := &sessdata.Payload{ | ||||
| 		LType: lType, | ||||
| 		PType: pType, | ||||
| 		Data:  data, | ||||
| 	} | ||||
| 	pl := getPayload() | ||||
| 	pl.LType = lType | ||||
| 	pl.PType = pType | ||||
| 	pl.Data = append(pl.Data, data...) | ||||
|  | ||||
| 	closed := false | ||||
|  | ||||
| 	select { | ||||
| 	case cSess.PayloadOutCstp <- payload: | ||||
| 	case cSess.PayloadOutCstp <- pl: | ||||
| 	case <-cSess.CloseChan: | ||||
| 		closed = true | ||||
| 	} | ||||
| @@ -62,14 +60,13 @@ func payloadOutCstp(cSess *sessdata.ConnSession, lType sessdata.LType, pType byt | ||||
| } | ||||
|  | ||||
| func payloadOutDtls(cSess *sessdata.ConnSession, dSess *sessdata.DtlsSession, lType sessdata.LType, pType byte, data []byte) bool { | ||||
| 	payload := &sessdata.Payload{ | ||||
| 		LType: lType, | ||||
| 		PType: pType, | ||||
| 		Data:  data, | ||||
| 	} | ||||
| 	pl := getPayload() | ||||
| 	pl.LType = lType | ||||
| 	pl.PType = pType | ||||
| 	pl.Data = append(pl.Data, data...) | ||||
|  | ||||
| 	select { | ||||
| 	case cSess.PayloadOutDtls <- payload: | ||||
| 	case cSess.PayloadOutDtls <- pl: | ||||
| 	case <-dSess.CloseChan: | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										52
									
								
								server/handler/pool.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								server/handler/pool.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| package handler | ||||
|  | ||||
| import ( | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/bjdgyc/anylink/sessdata" | ||||
| ) | ||||
|  | ||||
| var plPool = sync.Pool{ | ||||
| 	New: func() interface{} { | ||||
| 		pl := sessdata.Payload{ | ||||
| 			Data: make([]byte, 0, BufferSize), | ||||
| 		} | ||||
| 		// fmt.Println("plPool-init", len(pl.Data), cap(pl.Data)) | ||||
| 		return &pl | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func getPayload() *sessdata.Payload { | ||||
| 	pl := plPool.Get().(*sessdata.Payload) | ||||
| 	return pl | ||||
| } | ||||
|  | ||||
| func putPayload(pl *sessdata.Payload) { | ||||
| 	pl.LType = 0 | ||||
| 	pl.PType = 0 | ||||
| 	pl.Data = pl.Data[:0] | ||||
| 	plPool.Put(pl) | ||||
| } | ||||
|  | ||||
| var bytePool = sync.Pool{ | ||||
| 	New: func() interface{} { | ||||
| 		b := make([]byte, 0, BufferSize) | ||||
| 		// fmt.Println("bytePool-init") | ||||
| 		return b | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func getByteZero() []byte { | ||||
| 	b := bytePool.Get().([]byte) | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func getByteFull() []byte { | ||||
| 	b := bytePool.Get().([]byte) | ||||
| 	b = b[:BufferSize] | ||||
| 	return b | ||||
| } | ||||
| func putByte(b []byte) { | ||||
| 	b = b[:0] | ||||
| 	bytePool.Put(b) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user