mirror of https://github.com/bjdgyc/anylink.git
commit
2f593cc533
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:
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue