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 ©M 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 }