现在上级格式: YTpi#2.2.2.2:33080@1
说明:
YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
# 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#.
2.2.2.2:33080 是上级地址
@1 是设置权重,可以参考手册权重部分.
162 lines
4.4 KiB
Go
162 lines
4.4 KiB
Go
package sps
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net"
|
|
"runtime/debug"
|
|
"time"
|
|
|
|
"github.com/snail007/goproxy/utils"
|
|
goaes "github.com/snail007/goproxy/utils/aes"
|
|
"github.com/snail007/goproxy/utils/socks"
|
|
)
|
|
|
|
func (s *SPS) RunSSUDP(addr string) (err error) {
|
|
a, _ := net.ResolveUDPAddr("udp", addr)
|
|
listener, err := net.ListenUDP("udp", a)
|
|
if err != nil {
|
|
s.log.Printf("ss udp bind error %s", err)
|
|
return
|
|
}
|
|
s.log.Printf("ss udp on %s", listener.LocalAddr())
|
|
s.udpRelatedPacketConns.Set(addr, listener)
|
|
go func() {
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
|
|
}
|
|
}()
|
|
buf := utils.LeakyBuffer.Get()
|
|
defer utils.LeakyBuffer.Put(buf)
|
|
for {
|
|
n, srcAddr, err := listener.ReadFrom(buf)
|
|
if err != nil {
|
|
s.log.Printf("read from client error %s", err)
|
|
if utils.IsNetClosedErr(err) {
|
|
return
|
|
}
|
|
continue
|
|
}
|
|
var (
|
|
inconnRemoteAddr = srcAddr.String()
|
|
outUDPConn *net.UDPConn
|
|
outconn net.Conn
|
|
outconnLocalAddr string
|
|
destAddr *net.UDPAddr
|
|
clean = func(msg, err string) {
|
|
raddr := ""
|
|
if outUDPConn != nil {
|
|
raddr = outUDPConn.RemoteAddr().String()
|
|
outUDPConn.Close()
|
|
}
|
|
if msg != "" {
|
|
if raddr != "" {
|
|
s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr)
|
|
} else {
|
|
s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr)
|
|
}
|
|
}
|
|
s.userConns.Remove(inconnRemoteAddr)
|
|
if outconn != nil {
|
|
outconn.Close()
|
|
}
|
|
if outconnLocalAddr != "" {
|
|
s.userConns.Remove(outconnLocalAddr)
|
|
}
|
|
}
|
|
)
|
|
defer clean("", "")
|
|
|
|
raw := new(bytes.Buffer)
|
|
raw.Write([]byte{0x00, 0x00, 0x00})
|
|
raw.Write(s.localCipher.Decrypt(buf[:n]))
|
|
socksPacket := socks.NewPacketUDP()
|
|
err = socksPacket.Parse(raw.Bytes())
|
|
raw = nil
|
|
if err != nil {
|
|
s.log.Printf("udp parse error %s", err)
|
|
return
|
|
}
|
|
|
|
if v, ok := s.udpRelatedPacketConns.Get(inconnRemoteAddr); !ok {
|
|
//socks client
|
|
lbAddr := s.lb.Select(inconnRemoteAddr, *s.cfg.LoadBalanceOnlyHA)
|
|
outconn, err := s.GetParentConn(lbAddr)
|
|
if err != nil {
|
|
clean("connnect fail", fmt.Sprintf("%s", err))
|
|
return
|
|
}
|
|
|
|
client, err := s.HandshakeSocksParent(s.getParentAuth(lbAddr), &outconn, "udp", socksPacket.Addr(), socks.Auth{}, true)
|
|
if err != nil {
|
|
clean("handshake fail", fmt.Sprintf("%s", err))
|
|
return
|
|
}
|
|
|
|
outconnLocalAddr = outconn.LocalAddr().String()
|
|
s.userConns.Set(outconnLocalAddr, &outconn)
|
|
go func() {
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack()))
|
|
}
|
|
}()
|
|
buf := make([]byte, 1)
|
|
outconn.SetReadDeadline(time.Time{})
|
|
if _, err := outconn.Read(buf); err != nil {
|
|
clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err))
|
|
}
|
|
}()
|
|
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
|
|
localZeroAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
|
outUDPConn, err = net.DialUDP("udp", localZeroAddr, destAddr)
|
|
if err != nil {
|
|
s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
|
|
return
|
|
}
|
|
s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
|
|
utils.UDPCopy(listener, outUDPConn, srcAddr, time.Second*5, func(data []byte) []byte {
|
|
//forward to local
|
|
var v []byte
|
|
//convert parent data to raw
|
|
if len(s.udpParentKey) > 0 {
|
|
v, err = goaes.Decrypt(s.udpParentKey, data)
|
|
if err != nil {
|
|
s.log.Printf("udp outconn parse packet fail, %s", err.Error())
|
|
return []byte{}
|
|
}
|
|
} else {
|
|
v = data
|
|
}
|
|
return s.localCipher.Encrypt(v[3:])
|
|
}, func(err interface{}) {
|
|
s.udpRelatedPacketConns.Remove(srcAddr.String())
|
|
if err != nil {
|
|
s.log.Printf("udp out->local io copy crashed:\n%s\n%s", err, string(debug.Stack()))
|
|
}
|
|
})
|
|
} else {
|
|
outUDPConn = v.(*net.UDPConn)
|
|
}
|
|
//forward to parent
|
|
//p is raw, now convert it to parent
|
|
var v []byte
|
|
if len(s.udpParentKey) > 0 {
|
|
v, _ = goaes.Encrypt(s.udpParentKey, socksPacket.Bytes())
|
|
} else {
|
|
v = socksPacket.Bytes()
|
|
}
|
|
_, err = outUDPConn.Write(v)
|
|
socksPacket = socks.PacketUDP{}
|
|
if err != nil {
|
|
if utils.IsNetClosedErr(err) {
|
|
return
|
|
}
|
|
s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr)
|
|
}
|
|
}
|
|
}()
|
|
return
|
|
}
|