github.com/kelleygo/clashcore@v1.0.2/constant/metadata.go (about)

     1  package constant
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net"
     7  	"net/netip"
     8  	"strconv"
     9  
    10  	"github.com/kelleygo/clashcore/transport/socks5"
    11  )
    12  
    13  // Socks addr type
    14  const (
    15  	TCP NetWork = iota
    16  	UDP
    17  	ALLNet
    18  	InvalidNet = 0xff
    19  )
    20  
    21  const (
    22  	HTTP Type = iota
    23  	HTTPS
    24  	SOCKS4
    25  	SOCKS5
    26  	SHADOWSOCKS
    27  	VMESS
    28  	REDIR
    29  	TPROXY
    30  	TUNNEL
    31  	TUN
    32  	TUIC
    33  	HYSTERIA2
    34  	INNER
    35  )
    36  
    37  type NetWork int
    38  
    39  func (n NetWork) String() string {
    40  	switch n {
    41  	case TCP:
    42  		return "tcp"
    43  	case UDP:
    44  		return "udp"
    45  	case ALLNet:
    46  		return "all"
    47  	default:
    48  		return "invalid"
    49  	}
    50  }
    51  
    52  func (n NetWork) MarshalJSON() ([]byte, error) {
    53  	return json.Marshal(n.String())
    54  }
    55  
    56  type Type int
    57  
    58  func (t Type) String() string {
    59  	switch t {
    60  	case HTTP:
    61  		return "HTTP"
    62  	case HTTPS:
    63  		return "HTTPS"
    64  	case SOCKS4:
    65  		return "Socks4"
    66  	case SOCKS5:
    67  		return "Socks5"
    68  	case SHADOWSOCKS:
    69  		return "ShadowSocks"
    70  	case VMESS:
    71  		return "Vmess"
    72  	case REDIR:
    73  		return "Redir"
    74  	case TPROXY:
    75  		return "TProxy"
    76  	case TUNNEL:
    77  		return "Tunnel"
    78  	case TUN:
    79  		return "Tun"
    80  	case TUIC:
    81  		return "Tuic"
    82  	case HYSTERIA2:
    83  		return "Hysteria2"
    84  	case INNER:
    85  		return "Inner"
    86  	default:
    87  		return "Unknown"
    88  	}
    89  }
    90  
    91  func ParseType(t string) (*Type, error) {
    92  	var res Type
    93  	switch t {
    94  	case "HTTP":
    95  		res = HTTP
    96  	case "HTTPS":
    97  		res = HTTPS
    98  	case "SOCKS4":
    99  		res = SOCKS4
   100  	case "SOCKS5":
   101  		res = SOCKS5
   102  	case "SHADOWSOCKS":
   103  		res = SHADOWSOCKS
   104  	case "VMESS":
   105  		res = VMESS
   106  	case "REDIR":
   107  		res = REDIR
   108  	case "TPROXY":
   109  		res = TPROXY
   110  	case "TUNNEL":
   111  		res = TUNNEL
   112  	case "TUN":
   113  		res = TUN
   114  	case "TUIC":
   115  		res = TUIC
   116  	case "HYSTERIA2":
   117  		res = HYSTERIA2
   118  	case "INNER":
   119  		res = INNER
   120  	default:
   121  		return nil, fmt.Errorf("unknown type: %s", t)
   122  	}
   123  	return &res, nil
   124  }
   125  
   126  func (t Type) MarshalJSON() ([]byte, error) {
   127  	return json.Marshal(t.String())
   128  }
   129  
   130  // Metadata is used to store connection address
   131  type Metadata struct {
   132  	NetWork      NetWork    `json:"network"`
   133  	Type         Type       `json:"type"`
   134  	SrcIP        netip.Addr `json:"sourceIP"`
   135  	DstIP        netip.Addr `json:"destinationIP"`
   136  	DstGeoIP     []string   `json:"destinationGeoIP"` // can be nil if never queried, empty slice if got no result
   137  	DstIPASN     string     `json:"destinationIPASN"`
   138  	SrcPort      uint16     `json:"sourcePort,string"`      // `,string` is used to compatible with old version json output
   139  	DstPort      uint16     `json:"destinationPort,string"` // `,string` is used to compatible with old version json output
   140  	InIP         netip.Addr `json:"inboundIP"`
   141  	InPort       uint16     `json:"inboundPort,string"` // `,string` is used to compatible with old version json output
   142  	InName       string     `json:"inboundName"`
   143  	InUser       string     `json:"inboundUser"`
   144  	Host         string     `json:"host"`
   145  	DNSMode      DNSMode    `json:"dnsMode"`
   146  	Uid          uint32     `json:"uid"`
   147  	Process      string     `json:"process"`
   148  	ProcessPath  string     `json:"processPath"`
   149  	SpecialProxy string     `json:"specialProxy"`
   150  	SpecialRules string     `json:"specialRules"`
   151  	RemoteDst    string     `json:"remoteDestination"`
   152  	DSCP         uint8      `json:"dscp"`
   153  
   154  	RawSrcAddr net.Addr `json:"-"`
   155  	RawDstAddr net.Addr `json:"-"`
   156  	// Only domain rule
   157  	SniffHost string `json:"sniffHost"`
   158  }
   159  
   160  func (m *Metadata) RemoteAddress() string {
   161  	return net.JoinHostPort(m.String(), strconv.FormatUint(uint64(m.DstPort), 10))
   162  }
   163  
   164  func (m *Metadata) SourceAddress() string {
   165  	return net.JoinHostPort(m.SrcIP.String(), strconv.FormatUint(uint64(m.SrcPort), 10))
   166  }
   167  
   168  func (m *Metadata) SourceAddrPort() netip.AddrPort {
   169  	return netip.AddrPortFrom(m.SrcIP.Unmap(), m.SrcPort)
   170  }
   171  
   172  func (m *Metadata) SourceDetail() string {
   173  	if m.Type == INNER {
   174  		return fmt.Sprintf("%s", YiClashCoreName)
   175  	}
   176  
   177  	switch {
   178  	case m.Process != "" && m.Uid != 0:
   179  		return fmt.Sprintf("%s(%s, uid=%d)", m.SourceAddress(), m.Process, m.Uid)
   180  	case m.Uid != 0:
   181  		return fmt.Sprintf("%s(uid=%d)", m.SourceAddress(), m.Uid)
   182  	case m.Process != "":
   183  		return fmt.Sprintf("%s(%s)", m.SourceAddress(), m.Process)
   184  	default:
   185  		return fmt.Sprintf("%s", m.SourceAddress())
   186  	}
   187  }
   188  
   189  func (m *Metadata) SourceValid() bool {
   190  	return m.SrcPort != 0 && m.SrcIP.IsValid()
   191  }
   192  
   193  func (m *Metadata) AddrType() int {
   194  	switch true {
   195  	case m.Host != "" || !m.DstIP.IsValid():
   196  		return socks5.AtypDomainName
   197  	case m.DstIP.Is4():
   198  		return socks5.AtypIPv4
   199  	default:
   200  		return socks5.AtypIPv6
   201  	}
   202  }
   203  
   204  func (m *Metadata) Resolved() bool {
   205  	return m.DstIP.IsValid()
   206  }
   207  
   208  func (m *Metadata) RuleHost() string {
   209  	if len(m.SniffHost) == 0 {
   210  		return m.Host
   211  	} else {
   212  		return m.SniffHost
   213  	}
   214  }
   215  
   216  // Pure is used to solve unexpected behavior
   217  // when dialing proxy connection in DNSMapping mode.
   218  func (m *Metadata) Pure() *Metadata {
   219  	if (m.DNSMode == DNSMapping || m.DNSMode == DNSHosts) && m.DstIP.IsValid() {
   220  		copyM := *m
   221  		copyM.Host = ""
   222  		return &copyM
   223  	}
   224  
   225  	return m
   226  }
   227  
   228  func (m *Metadata) AddrPort() netip.AddrPort {
   229  	return netip.AddrPortFrom(m.DstIP.Unmap(), m.DstPort)
   230  }
   231  
   232  func (m *Metadata) UDPAddr() *net.UDPAddr {
   233  	if m.NetWork != UDP || !m.DstIP.IsValid() {
   234  		return nil
   235  	}
   236  	return net.UDPAddrFromAddrPort(m.AddrPort())
   237  }
   238  
   239  func (m *Metadata) String() string {
   240  	if m.Host != "" {
   241  		return m.Host
   242  	} else if m.DstIP.IsValid() {
   243  		return m.DstIP.String()
   244  	} else {
   245  		return "<nil>"
   246  	}
   247  }
   248  
   249  func (m *Metadata) Valid() bool {
   250  	return m.Host != "" || m.DstIP.IsValid()
   251  }
   252  
   253  func (m *Metadata) SetRemoteAddr(addr net.Addr) error {
   254  	if addr == nil {
   255  		return nil
   256  	}
   257  	if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok {
   258  		if rawAddr := rawAddr.RawAddr(); rawAddr != nil {
   259  			if err := m.SetRemoteAddr(rawAddr); err == nil {
   260  				return nil
   261  			}
   262  		}
   263  	}
   264  	if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { // *net.TCPAddr, *net.UDPAddr, M.Socksaddr
   265  		if addrPort := addr.AddrPort(); addrPort.Port() != 0 {
   266  			m.DstPort = addrPort.Port()
   267  			if addrPort.IsValid() { // sing's M.Socksaddr maybe return an invalid AddrPort if it's a DomainName
   268  				m.DstIP = addrPort.Addr().Unmap()
   269  				return nil
   270  			} else {
   271  				if addr, ok := addr.(interface{ AddrString() string }); ok { // must be sing's M.Socksaddr
   272  					m.Host = addr.AddrString() // actually is M.Socksaddr.Fqdn
   273  					return nil
   274  				}
   275  			}
   276  		}
   277  	}
   278  	return m.SetRemoteAddress(addr.String())
   279  }
   280  
   281  func (m *Metadata) SetRemoteAddress(rawAddress string) error {
   282  	host, port, err := net.SplitHostPort(rawAddress)
   283  	if err != nil {
   284  		return err
   285  	}
   286  
   287  	var uint16Port uint16
   288  	if port, err := strconv.ParseUint(port, 10, 16); err == nil {
   289  		uint16Port = uint16(port)
   290  	}
   291  
   292  	if ip, err := netip.ParseAddr(host); err != nil {
   293  		m.Host = host
   294  		m.DstIP = netip.Addr{}
   295  	} else {
   296  		m.Host = ""
   297  		m.DstIP = ip.Unmap()
   298  	}
   299  	m.DstPort = uint16Port
   300  
   301  	return nil
   302  }