github.com/yaling888/clash@v1.53.0/constant/tun.go (about) 1 package constant 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/netip" 8 "strconv" 9 "strings" 10 ) 11 12 var StackTypeMapping = map[string]TUNStack{ 13 strings.ToUpper(TunGvisor.String()): TunGvisor, 14 strings.ToUpper(TunSystem.String()): TunSystem, 15 } 16 17 const ( 18 TunGvisor TUNStack = iota 19 TunSystem 20 ) 21 22 const ( 23 TunDisabled TUNState = iota 24 TunEnabled 25 TunPaused 26 ) 27 28 type TUNState int 29 30 type TUNChangeCallback interface { 31 Pause() 32 Resume() 33 } 34 35 // Tun config 36 type Tun struct { 37 Enable bool `yaml:"enable" json:"enable"` 38 Device string `yaml:"device" json:"device"` 39 Stack TUNStack `yaml:"stack" json:"stack"` 40 DNSHijack []DNSUrl `yaml:"dns-hijack" json:"dns-hijack"` 41 AutoRoute bool `yaml:"auto-route" json:"auto-route"` 42 AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` 43 TunAddressPrefix *netip.Prefix `yaml:"-" json:"-"` 44 RedirectToTun []string `yaml:"-" json:"-"` 45 StopRouteListener bool `yaml:"-" json:"-"` 46 } 47 48 var lastTunConf *Tun 49 50 func GetLastTunConf() *Tun { 51 return lastTunConf 52 } 53 54 func SetLastTunConf(conf *Tun) { 55 lastTunConf = conf 56 } 57 58 // GetTunConf returns the last tun config 59 func GetTunConf() Tun { 60 if lastTunConf == nil { 61 addrPort := DNSAddrPort{ 62 AddrPort: netip.MustParseAddrPort("0.0.0.0:53"), 63 } 64 return Tun{ 65 Enable: false, 66 Stack: TunGvisor, 67 DNSHijack: []DNSUrl{ // default hijack all dns query 68 { 69 Network: "udp", 70 AddrPort: addrPort, 71 }, 72 { 73 Network: "tcp", 74 AddrPort: addrPort, 75 }, 76 }, 77 AutoRoute: true, 78 AutoDetectInterface: false, 79 } 80 } 81 return *lastTunConf 82 } 83 84 type TUNStack int 85 86 // UnmarshalYAML unserialize TUNStack with yaml 87 func (e *TUNStack) UnmarshalYAML(unmarshal func(any) error) error { 88 var tp string 89 if err := unmarshal(&tp); err != nil { 90 return err 91 } 92 mode, exist := StackTypeMapping[strings.ToUpper(tp)] 93 if !exist { 94 return errors.New("invalid tun stack") 95 } 96 *e = mode 97 return nil 98 } 99 100 // MarshalYAML serialize TUNStack with yaml 101 func (e TUNStack) MarshalYAML() (any, error) { 102 return e.String(), nil 103 } 104 105 // UnmarshalJSON unserialize TUNStack with json 106 func (e *TUNStack) UnmarshalJSON(data []byte) error { 107 var tp string 108 _ = json.Unmarshal(data, &tp) 109 mode, exist := StackTypeMapping[strings.ToUpper(tp)] 110 if !exist { 111 return errors.New("invalid tun stack") 112 } 113 *e = mode 114 return nil 115 } 116 117 // MarshalJSON serialize TUNStack with json 118 func (e TUNStack) MarshalJSON() ([]byte, error) { 119 return json.Marshal(e.String()) 120 } 121 122 func (e TUNStack) String() string { 123 switch e { 124 case TunGvisor: 125 return "gVisor" 126 case TunSystem: 127 return "System" 128 default: 129 return "unknown" 130 } 131 } 132 133 type DNSAddrPort struct { 134 netip.AddrPort 135 } 136 137 func (p *DNSAddrPort) UnmarshalText(text []byte) error { 138 if len(text) == 0 { 139 *p = DNSAddrPort{} 140 return nil 141 } 142 143 addrPort := string(text) 144 if strings.HasPrefix(addrPort, "any") { 145 _, port, _ := strings.Cut(addrPort, "any") 146 addrPort = "0.0.0.0" + port 147 } 148 149 ap, err := netip.ParseAddrPort(addrPort) 150 *p = DNSAddrPort{AddrPort: ap} 151 return err 152 } 153 154 func (p DNSAddrPort) String() string { 155 addrPort := p.AddrPort.String() 156 if p.AddrPort.Addr().IsUnspecified() { 157 addrPort = "any:" + strconv.Itoa(int(p.AddrPort.Port())) 158 } 159 return addrPort 160 } 161 162 type DNSUrl struct { 163 Network string 164 AddrPort DNSAddrPort 165 } 166 167 func (d *DNSUrl) UnmarshalYAML(unmarshal func(any) error) error { 168 var text string 169 if err := unmarshal(&text); err != nil { 170 return err 171 } 172 173 text = strings.ToLower(text) 174 network := "udp" 175 if before, after, found := strings.Cut(text, "://"); found { 176 network = before 177 text = after 178 } 179 180 if network != "udp" && network != "tcp" { 181 return errors.New("invalid dns url schema") 182 } 183 184 ap := &DNSAddrPort{} 185 if err := ap.UnmarshalText([]byte(text)); err != nil { 186 return err 187 } 188 189 *d = DNSUrl{Network: network, AddrPort: *ap} 190 191 return nil 192 } 193 194 func (d DNSUrl) MarshalYAML() (any, error) { 195 return d.String(), nil 196 } 197 198 func (d *DNSUrl) UnmarshalJSON(data []byte) error { 199 var text string 200 if err := json.Unmarshal(data, &text); err != nil { 201 return err 202 } 203 204 text = strings.ToLower(text) 205 network := "udp" 206 if before, after, found := strings.Cut(text, "://"); found { 207 network = before 208 text = after 209 } 210 211 if network != "udp" && network != "tcp" { 212 return errors.New("invalid dns url schema") 213 } 214 215 ap := &DNSAddrPort{} 216 if err := ap.UnmarshalText([]byte(text)); err != nil { 217 return err 218 } 219 220 *d = DNSUrl{Network: network, AddrPort: *ap} 221 222 return nil 223 } 224 225 func (d DNSUrl) MarshalJSON() ([]byte, error) { 226 return json.Marshal(d.String()) 227 } 228 229 func (d DNSUrl) String() string { 230 return fmt.Sprintf("%s://%s", d.Network, d.AddrPort) 231 }