Clash.Meta/adapters/outbound/vmess.go

130 lines
3.5 KiB
Go
Raw Normal View History

2019-12-08 12:17:24 +08:00
package outbound
2018-09-06 10:53:29 +08:00
import (
"context"
2018-09-06 10:53:29 +08:00
"fmt"
"net"
"strconv"
"strings"
2018-09-30 12:25:52 +08:00
"github.com/Dreamacro/clash/component/vmess"
2018-09-06 10:53:29 +08:00
C "github.com/Dreamacro/clash/constant"
)
type Vmess struct {
2018-12-22 23:56:42 +08:00
*Base
2018-09-06 10:53:29 +08: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 16:32:15 +08: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"`
}
func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
c, err := dialContext(ctx, "tcp", v.server)
2018-09-06 10:53:29 +08:00
if err != nil {
2018-11-21 13:47:46 +08:00
return nil, fmt.Errorf("%s connect error", v.server)
2018-09-06 10:53:29 +08:00
}
tcpKeepAlive(c)
2018-11-21 13:47:46 +08:00
c, err = v.client.New(c, parseVmessAddr(metadata))
return newConn(c, v), err
2018-11-21 13:47:46 +08:00
}
func (v *Vmess) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
ctx, cancel := context.WithTimeout(context.Background(), tcpTimeout)
defer cancel()
c, err := dialContext(ctx, "tcp", v.server)
2019-04-25 16:32:15 +08:00
if err != nil {
return nil, nil, fmt.Errorf("%s connect error", v.server)
}
tcpKeepAlive(c)
c, err = v.client.New(c, parseVmessAddr(metadata))
if err != nil {
return nil, nil, fmt.Errorf("new vmess client error: %v", err)
}
2019-10-11 20:11:18 +08:00
return newPacketConn(&vmessUDPConn{Conn: c}, v), c.RemoteAddr(), nil
2019-04-25 16:32:15 +08:00
}
func NewVmess(option VmessOption) (*Vmess, error) {
security := strings.ToLower(option.Cipher)
2018-09-06 10:53:29 +08: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,
2019-07-29 12:25:29 +08:00
SessionCache: getClientSessionCache(),
2018-09-06 10:53:29 +08:00
})
if err != nil {
return nil, err
}
2018-09-08 19:53:24 +08:00
2018-09-06 10:53:29 +08:00
return &Vmess{
2018-12-22 23:56:42 +08:00
Base: &Base{
name: option.Name,
tp: C.Vmess,
udp: true,
2018-12-22 23:56:42 +08:00
},
2018-11-04 21:12:16 +08:00
server: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
2018-09-06 10:53:29 +08:00
client: client,
}, nil
}
2018-09-30 12:25:52 +08:00
func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr {
2018-09-06 10:53:29 +08:00
var addrType byte
var addr []byte
2018-09-30 12:25:52 +08:00
switch metadata.AddrType {
2018-09-06 10:53:29 +08:00
case C.AtypIPv4:
addrType = byte(vmess.AtypIPv4)
addr = make([]byte, net.IPv4len)
2019-05-09 21:00:29 +08:00
copy(addr[:], metadata.DstIP.To4())
2018-09-06 10:53:29 +08:00
case C.AtypIPv6:
addrType = byte(vmess.AtypIPv6)
addr = make([]byte, net.IPv6len)
2019-05-09 21:00:29 +08:00
copy(addr[:], metadata.DstIP.To16())
2018-09-06 10:53:29 +08:00
case C.AtypDomainName:
addrType = byte(vmess.AtypDomainName)
2018-09-30 12:25:52 +08:00
addr = make([]byte, len(metadata.Host)+1)
addr[0] = byte(len(metadata.Host))
copy(addr[1:], []byte(metadata.Host))
2018-09-06 10:53:29 +08:00
}
2019-05-09 21:00:29 +08:00
port, _ := strconv.Atoi(metadata.DstPort)
2018-09-06 10:53:29 +08:00
return &vmess.DstAddr{
2019-04-25 16:32:15 +08:00
UDP: metadata.NetWork == C.UDP,
2018-09-06 10:53:29 +08:00
AddrType: addrType,
Addr: addr,
Port: uint(port),
}
}
2019-10-11 20:11:18 +08:00
type vmessUDPConn struct {
net.Conn
}
func (uc *vmessUDPConn) WriteTo(b []byte, addr net.Addr) (int, error) {
return uc.Conn.Write(b)
}
func (uc *vmessUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
n, err := uc.Conn.Read(b)
return n, uc.RemoteAddr(), err
}