diff --git a/README.md b/README.md index 6197d73c..48ed9dc0 100644 --- a/README.md +++ b/README.md @@ -230,5 +230,5 @@ https://clash.gitbook.io/ - [x] Complementing the necessary rule operators - [x] Redir proxy -- [ ] UDP support (vmess) +- [x] UDP support - [ ] Connection manager diff --git a/adapters/outbound/vmess.go b/adapters/outbound/vmess.go index 6c137432..823469f7 100644 --- a/adapters/outbound/vmess.go +++ b/adapters/outbound/vmess.go @@ -24,6 +24,7 @@ type VmessOption struct { AlterID int `proxy:"alterId"` Cipher string `proxy:"cipher"` TLS bool `proxy:"tls,omitempty"` + UDP bool `proxy:"udp,omitempty"` Network string `proxy:"network,omitempty"` WSPath string `proxy:"ws-path,omitempty"` WSHeaders map[string]string `proxy:"ws-headers,omitempty"` @@ -40,6 +41,16 @@ func (v *Vmess) Dial(metadata *C.Metadata) (net.Conn, error) { return c, err } +func (v *Vmess) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) { + c, err := net.DialTimeout("tcp", v.server, tcpTimeout) + if err != nil { + return nil, nil, fmt.Errorf("%s connect error", v.server) + } + tcpKeepAlive(c) + c, err = v.client.New(c, parseVmessAddr(metadata)) + return &fakeUDPConn{Conn: c}, c.LocalAddr(), err +} + func NewVmess(option VmessOption) (*Vmess, error) { security := strings.ToLower(option.Cipher) client, err := vmess.NewClient(vmess.Config{ @@ -63,6 +74,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { Base: &Base{ name: option.Name, tp: C.Vmess, + udp: option.UDP, }, server: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), client: client, @@ -90,6 +102,7 @@ func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr { port, _ := strconv.Atoi(metadata.Port) return &vmess.DstAddr{ + UDP: metadata.NetWork == C.UDP, AddrType: addrType, Addr: addr, Port: uint(port), diff --git a/component/vmess/conn.go b/component/vmess/conn.go index 15b1e05c..44ff57ee 100644 --- a/component/vmess/conn.go +++ b/component/vmess/conn.go @@ -77,7 +77,11 @@ func (vc *Conn) sendRequest() error { // P Sec Reserve Cmd buf.WriteByte(byte(p<<4) | byte(vc.security)) buf.WriteByte(0) - buf.WriteByte(CommandTCP) + if vc.dst.UDP { + buf.WriteByte(CommandUDP) + } else { + buf.WriteByte(CommandTCP) + } // Port AddrType Addr binary.Write(buf, binary.BigEndian, uint16(vc.dst.Port)) diff --git a/component/vmess/vmess.go b/component/vmess/vmess.go index 71b30c15..23a7b508 100644 --- a/component/vmess/vmess.go +++ b/component/vmess/vmess.go @@ -57,6 +57,7 @@ const ( // DstAddr store destination address type DstAddr struct { + UDP bool AddrType byte Addr []byte Port uint