mirror of
				https://github.com/xjasonlyu/tun2socks.git
				synced 2025-10-31 03:56:30 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			125 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package engine
 | |
| 
 | |
| import (
 | |
| 	"encoding/base64"
 | |
| 	"fmt"
 | |
| 	"net/url"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/xjasonlyu/tun2socks/v2/core/device"
 | |
| 	"github.com/xjasonlyu/tun2socks/v2/core/device/fdbased"
 | |
| 	"github.com/xjasonlyu/tun2socks/v2/core/device/tun"
 | |
| 	"github.com/xjasonlyu/tun2socks/v2/proxy"
 | |
| 	"github.com/xjasonlyu/tun2socks/v2/proxy/proto"
 | |
| )
 | |
| 
 | |
| func parseDevice(s string, mtu uint32) (device.Device, error) {
 | |
| 	if !strings.Contains(s, "://") {
 | |
| 		s = fmt.Sprintf("%s://%s", tun.Driver /* default driver */, s)
 | |
| 	}
 | |
| 
 | |
| 	u, err := url.Parse(s)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	name := u.Host
 | |
| 	driver := strings.ToLower(u.Scheme)
 | |
| 
 | |
| 	switch driver {
 | |
| 	case fdbased.Driver:
 | |
| 		return fdbased.Open(name, mtu)
 | |
| 	case tun.Driver:
 | |
| 		return tun.Open(name, mtu)
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("unsupported driver: %s", driver)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func parseProxy(s string) (proxy.Proxy, error) {
 | |
| 	if !strings.Contains(s, "://") {
 | |
| 		s = fmt.Sprintf("%s://%s", proto.Socks5 /* default protocol */, s)
 | |
| 	}
 | |
| 
 | |
| 	u, err := url.Parse(s)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	protocol := strings.ToLower(u.Scheme)
 | |
| 
 | |
| 	switch protocol {
 | |
| 	case proto.Direct.String():
 | |
| 		return proxy.NewDirect(), nil
 | |
| 	case proto.Reject.String():
 | |
| 		return proxy.NewReject(), nil
 | |
| 	case proto.HTTP.String():
 | |
| 		return proxy.NewHTTP(parseHTTP(u))
 | |
| 	case proto.Socks4.String():
 | |
| 		return proxy.NewSocks4(parseSocks4(u))
 | |
| 	case proto.Socks5.String():
 | |
| 		return proxy.NewSocks5(parseSocks5(u))
 | |
| 	case proto.Shadowsocks.String():
 | |
| 		return proxy.NewShadowsocks(parseShadowsocks(u))
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("unsupported protocol: %s", protocol)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func parseHTTP(u *url.URL) (address, username, password string) {
 | |
| 	address, username = u.Host, u.User.Username()
 | |
| 	password, _ = u.User.Password()
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func parseSocks4(u *url.URL) (address, username string) {
 | |
| 	address, username = u.Host, u.User.Username()
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func parseSocks5(u *url.URL) (address, username, password string) {
 | |
| 	address, username = u.Host, u.User.Username()
 | |
| 	password, _ = u.User.Password()
 | |
| 
 | |
| 	// Socks5 over UDS
 | |
| 	if address == "" {
 | |
| 		address = u.Path
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func parseShadowsocks(u *url.URL) (address, method, password, obfsMode, obfsHost string) {
 | |
| 	address = u.Host
 | |
| 
 | |
| 	if pass, set := u.User.Password(); set {
 | |
| 		method = u.User.Username()
 | |
| 		password = pass
 | |
| 	} else {
 | |
| 		data, _ := base64.RawURLEncoding.DecodeString(u.User.String())
 | |
| 		userInfo := strings.SplitN(string(data), ":", 2)
 | |
| 		if len(userInfo) == 2 {
 | |
| 			method = userInfo[0]
 | |
| 			password = userInfo[1]
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	rawQuery, _ := url.QueryUnescape(u.RawQuery)
 | |
| 	for _, s := range strings.Split(rawQuery, ";") {
 | |
| 		data := strings.SplitN(s, "=", 2)
 | |
| 		if len(data) != 2 {
 | |
| 			continue
 | |
| 		}
 | |
| 		key := data[0]
 | |
| 		value := data[1]
 | |
| 
 | |
| 		switch key {
 | |
| 		case "obfs":
 | |
| 			obfsMode = value
 | |
| 		case "obfs-host":
 | |
| 			obfsHost = value
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | 
