clash/adapters/outbound/vmess.go

111 lines
3 KiB
Go
Raw Normal View History

2018-09-06 02:53:29 +00:00
package adapters
import (
"fmt"
"net"
"strconv"
"strings"
2018-09-30 04:25:52 +00:00
"github.com/Dreamacro/clash/component/vmess"
2018-09-06 02:53:29 +00:00
C "github.com/Dreamacro/clash/constant"
)
type Vmess struct {
2018-12-22 15:56:42 +00:00
*Base
2018-09-06 02:53:29 +00:00
server string
client *vmess.Client
}
type VmessOption struct {
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
UUID string `proxy:"uuid"`
AlterID int `proxy:"alterId"`
Cipher string `proxy:"cipher"`
TLS bool `proxy:"tls,omitempty"`
2019-04-25 08:32:15 +00:00
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
WSPath string `proxy:"ws-path,omitempty"`
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
}
2019-03-03 03:59:07 +00:00
func (v *Vmess) Dial(metadata *C.Metadata) (net.Conn, error) {
c, err := dialTimeout("tcp", v.server, tcpTimeout)
2018-09-06 02:53:29 +00:00
if err != nil {
2018-11-21 05:47:46 +00:00
return nil, fmt.Errorf("%s connect error", v.server)
2018-09-06 02:53:29 +00:00
}
tcpKeepAlive(c)
2018-11-21 05:47:46 +00:00
c, err = v.client.New(c, parseVmessAddr(metadata))
2018-12-22 15:56:42 +00:00
return c, err
2018-11-21 05:47:46 +00:00
}
2019-04-25 08:32:15 +00:00
func (v *Vmess) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
c, err := dialTimeout("tcp", v.server, tcpTimeout)
2019-04-25 08:32:15 +00:00
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)
2018-09-06 02:53:29 +00:00
client, err := vmess.NewClient(vmess.Config{
UUID: option.UUID,
AlterID: uint16(option.AlterID),
Security: security,
TLS: option.TLS,
HostName: option.Server,
Port: strconv.Itoa(option.Port),
NetWork: option.Network,
WebSocketPath: option.WSPath,
WebSocketHeaders: option.WSHeaders,
SkipCertVerify: option.SkipCertVerify,
SessionCacahe: getClientSessionCache(),
2018-09-06 02:53:29 +00:00
})
if err != nil {
return nil, err
}
2018-09-08 11:53:24 +00:00
2018-09-06 02:53:29 +00:00
return &Vmess{
2018-12-22 15:56:42 +00:00
Base: &Base{
name: option.Name,
tp: C.Vmess,
2019-04-25 08:32:15 +00:00
udp: option.UDP,
2018-12-22 15:56:42 +00:00
},
2018-11-04 13:12:16 +00:00
server: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
2018-09-06 02:53:29 +00:00
client: client,
}, nil
}
2018-09-30 04:25:52 +00:00
func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr {
2018-09-06 02:53:29 +00:00
var addrType byte
var addr []byte
2018-09-30 04:25:52 +00:00
switch metadata.AddrType {
2018-09-06 02:53:29 +00:00
case C.AtypIPv4:
addrType = byte(vmess.AtypIPv4)
addr = make([]byte, net.IPv4len)
2019-05-09 13:00:29 +00:00
copy(addr[:], metadata.DstIP.To4())
2018-09-06 02:53:29 +00:00
case C.AtypIPv6:
addrType = byte(vmess.AtypIPv6)
addr = make([]byte, net.IPv6len)
2019-05-09 13:00:29 +00:00
copy(addr[:], metadata.DstIP.To16())
2018-09-06 02:53:29 +00:00
case C.AtypDomainName:
addrType = byte(vmess.AtypDomainName)
2018-09-30 04:25:52 +00:00
addr = make([]byte, len(metadata.Host)+1)
addr[0] = byte(len(metadata.Host))
copy(addr[1:], []byte(metadata.Host))
2018-09-06 02:53:29 +00:00
}
2019-05-09 13:00:29 +00:00
port, _ := strconv.Atoi(metadata.DstPort)
2018-09-06 02:53:29 +00:00
return &vmess.DstAddr{
2019-04-25 08:32:15 +00:00
UDP: metadata.NetWork == C.UDP,
2018-09-06 02:53:29 +00:00
AddrType: addrType,
Addr: addr,
Port: uint(port),
}
}