github.com/metacubex/mihomo@v1.18.5/listener/sing_vmess/server.go (about)

     1  package sing_vmess
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"net"
     7  	"net/http"
     8  	"net/url"
     9  	"strings"
    10  
    11  	"github.com/metacubex/mihomo/adapter/inbound"
    12  	N "github.com/metacubex/mihomo/common/net"
    13  	C "github.com/metacubex/mihomo/constant"
    14  	LC "github.com/metacubex/mihomo/listener/config"
    15  	"github.com/metacubex/mihomo/listener/sing"
    16  	"github.com/metacubex/mihomo/ntp"
    17  	mihomoVMess "github.com/metacubex/mihomo/transport/vmess"
    18  
    19  	vmess "github.com/metacubex/sing-vmess"
    20  	"github.com/sagernet/sing/common"
    21  	"github.com/sagernet/sing/common/metadata"
    22  )
    23  
    24  type Listener struct {
    25  	closed    bool
    26  	config    LC.VmessServer
    27  	listeners []net.Listener
    28  	service   *vmess.Service[string]
    29  }
    30  
    31  var _listener *Listener
    32  
    33  func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) (sl *Listener, err error) {
    34  	if len(additions) == 0 {
    35  		additions = []inbound.Addition{
    36  			inbound.WithInName("DEFAULT-VMESS"),
    37  			inbound.WithSpecialRules(""),
    38  		}
    39  		defer func() {
    40  			_listener = sl
    41  		}()
    42  	}
    43  	h, err := sing.NewListenerHandler(sing.ListenerConfig{
    44  		Tunnel:    tunnel,
    45  		Type:      C.VMESS,
    46  		Additions: additions,
    47  		MuxOption: config.MuxOption,
    48  	})
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	service := vmess.NewService[string](h, vmess.ServiceWithDisableHeaderProtection(), vmess.ServiceWithTimeFunc(ntp.Now))
    54  	err = service.UpdateUsers(
    55  		common.Map(config.Users, func(it LC.VmessUser) string {
    56  			return it.Username
    57  		}),
    58  		common.Map(config.Users, func(it LC.VmessUser) string {
    59  			return it.UUID
    60  		}),
    61  		common.Map(config.Users, func(it LC.VmessUser) int {
    62  			return it.AlterID
    63  		}))
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	err = service.Start()
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	sl = &Listener{false, config, nil, service}
    74  
    75  	tlsConfig := &tls.Config{}
    76  	var httpMux *http.ServeMux
    77  
    78  	if config.Certificate != "" && config.PrivateKey != "" {
    79  		cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path)
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  		tlsConfig.Certificates = []tls.Certificate{cert}
    84  	}
    85  	if config.WsPath != "" {
    86  		httpMux = http.NewServeMux()
    87  		httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) {
    88  			conn, err := mihomoVMess.StreamUpgradedWebsocketConn(w, r)
    89  			if err != nil {
    90  				http.Error(w, err.Error(), 500)
    91  				return
    92  			}
    93  			sl.HandleConn(conn, tunnel)
    94  		})
    95  		tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1")
    96  	}
    97  
    98  	for _, addr := range strings.Split(config.Listen, ",") {
    99  		addr := addr
   100  
   101  		//TCP
   102  		l, err := inbound.Listen("tcp", addr)
   103  		if err != nil {
   104  			return nil, err
   105  		}
   106  		if len(tlsConfig.Certificates) > 0 {
   107  			l = tls.NewListener(l, tlsConfig)
   108  		}
   109  		sl.listeners = append(sl.listeners, l)
   110  
   111  		go func() {
   112  			if httpMux != nil {
   113  				_ = http.Serve(l, httpMux)
   114  				return
   115  			}
   116  			for {
   117  				c, err := l.Accept()
   118  				if err != nil {
   119  					if sl.closed {
   120  						break
   121  					}
   122  					continue
   123  				}
   124  				N.TCPKeepAlive(c)
   125  
   126  				go sl.HandleConn(c, tunnel)
   127  			}
   128  		}()
   129  	}
   130  
   131  	return sl, nil
   132  }
   133  
   134  func (l *Listener) Close() error {
   135  	l.closed = true
   136  	var retErr error
   137  	for _, lis := range l.listeners {
   138  		err := lis.Close()
   139  		if err != nil {
   140  			retErr = err
   141  		}
   142  	}
   143  	err := l.service.Close()
   144  	if err != nil {
   145  		retErr = err
   146  	}
   147  	return retErr
   148  }
   149  
   150  func (l *Listener) Config() string {
   151  	return l.config.String()
   152  }
   153  
   154  func (l *Listener) AddrList() (addrList []net.Addr) {
   155  	for _, lis := range l.listeners {
   156  		addrList = append(addrList, lis.Addr())
   157  	}
   158  	return
   159  }
   160  
   161  func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
   162  	ctx := sing.WithAdditions(context.TODO(), additions...)
   163  	err := l.service.NewConnection(ctx, conn, metadata.Metadata{
   164  		Protocol: "vmess",
   165  		Source:   metadata.ParseSocksaddr(conn.RemoteAddr().String()),
   166  	})
   167  	if err != nil {
   168  		_ = conn.Close()
   169  		return
   170  	}
   171  }
   172  
   173  func HandleVmess(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) bool {
   174  	if _listener != nil && _listener.service != nil {
   175  		go _listener.HandleConn(conn, tunnel, additions...)
   176  		return true
   177  	}
   178  	return false
   179  }
   180  
   181  func ParseVmessURL(s string) (addr, username, password string, err error) {
   182  	u, err := url.Parse(s)
   183  	if err != nil {
   184  		return
   185  	}
   186  
   187  	addr = u.Host
   188  	if u.User != nil {
   189  		username = u.User.Username()
   190  		password, _ = u.User.Password()
   191  	}
   192  	return
   193  }