github.com/metacubex/mihomo@v1.18.5/transport/vmess/vmess.go (about)

     1  package vmess
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"runtime"
     7  
     8  	"github.com/metacubex/mihomo/common/utils"
     9  
    10  	"github.com/gofrs/uuid/v5"
    11  	"github.com/zhangyunhao116/fastrand"
    12  )
    13  
    14  // Version of vmess
    15  const Version byte = 1
    16  
    17  // Request Options
    18  const (
    19  	OptionChunkStream  byte = 1
    20  	OptionChunkMasking byte = 4
    21  )
    22  
    23  // Security type vmess
    24  type Security = byte
    25  
    26  // Cipher types
    27  const (
    28  	SecurityAES128GCM        Security = 3
    29  	SecurityCHACHA20POLY1305 Security = 4
    30  	SecurityNone             Security = 5
    31  )
    32  
    33  // CipherMapping return
    34  var CipherMapping = map[string]byte{
    35  	"none":              SecurityNone,
    36  	"aes-128-gcm":       SecurityAES128GCM,
    37  	"chacha20-poly1305": SecurityCHACHA20POLY1305,
    38  }
    39  
    40  // Command types
    41  const (
    42  	CommandTCP byte = 1
    43  	CommandUDP byte = 2
    44  )
    45  
    46  // Addr types
    47  const (
    48  	AtypIPv4       byte = 1
    49  	AtypDomainName byte = 2
    50  	AtypIPv6       byte = 3
    51  )
    52  
    53  // DstAddr store destination address
    54  type DstAddr struct {
    55  	UDP      bool
    56  	AddrType byte
    57  	Addr     []byte
    58  	Port     uint
    59  }
    60  
    61  // Client is vmess connection generator
    62  type Client struct {
    63  	user     []*ID
    64  	uuid     *uuid.UUID
    65  	security Security
    66  	isAead   bool
    67  }
    68  
    69  // Config of vmess
    70  type Config struct {
    71  	UUID     string
    72  	AlterID  uint16
    73  	Security string
    74  	Port     string
    75  	HostName string
    76  	IsAead   bool
    77  }
    78  
    79  // StreamConn return a Conn with net.Conn and DstAddr
    80  func (c *Client) StreamConn(conn net.Conn, dst *DstAddr) (net.Conn, error) {
    81  	r := fastrand.Intn(len(c.user))
    82  	return newConn(conn, c.user[r], dst, c.security, c.isAead)
    83  }
    84  
    85  // NewClient return Client instance
    86  func NewClient(config Config) (*Client, error) {
    87  	uid, err := utils.UUIDMap(config.UUID)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	var security Security
    93  	switch config.Security {
    94  	case "aes-128-gcm":
    95  		security = SecurityAES128GCM
    96  	case "chacha20-poly1305":
    97  		security = SecurityCHACHA20POLY1305
    98  	case "none":
    99  		security = SecurityNone
   100  	case "auto":
   101  		security = SecurityCHACHA20POLY1305
   102  		if runtime.GOARCH == "amd64" || runtime.GOARCH == "s390x" || runtime.GOARCH == "arm64" {
   103  			security = SecurityAES128GCM
   104  		}
   105  	default:
   106  		return nil, fmt.Errorf("unknown security type: %s", config.Security)
   107  	}
   108  
   109  	return &Client{
   110  		user:     newAlterIDs(newID(&uid), config.AlterID),
   111  		uuid:     &uid,
   112  		security: security,
   113  		isAead:   config.IsAead,
   114  	}, nil
   115  }