github.com/metacubex/mihomo@v1.18.5/listener/config/tunnel.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "net" 6 "strings" 7 8 "github.com/samber/lo" 9 ) 10 11 type tunnel struct { 12 Network []string `yaml:"network"` 13 Address string `yaml:"address"` 14 Target string `yaml:"target"` 15 Proxy string `yaml:"proxy"` 16 } 17 18 type Tunnel tunnel 19 20 // UnmarshalYAML implements yaml.Unmarshaler 21 func (t *Tunnel) UnmarshalYAML(unmarshal func(any) error) error { 22 var tp string 23 if err := unmarshal(&tp); err != nil { 24 var inner tunnel 25 if err := unmarshal(&inner); err != nil { 26 return err 27 } 28 29 *t = Tunnel(inner) 30 return nil 31 } 32 33 // parse udp/tcp,address,target,proxy 34 parts := lo.Map(strings.Split(tp, ","), func(s string, _ int) string { 35 return strings.TrimSpace(s) 36 }) 37 if len(parts) != 3 && len(parts) != 4 { 38 return fmt.Errorf("invalid tunnel config %s", tp) 39 } 40 network := strings.Split(parts[0], "/") 41 42 // validate network 43 for _, n := range network { 44 switch n { 45 case "tcp", "udp": 46 default: 47 return fmt.Errorf("invalid tunnel network %s", n) 48 } 49 } 50 51 // validate address and target 52 address := parts[1] 53 target := parts[2] 54 for _, addr := range []string{address, target} { 55 if _, _, err := net.SplitHostPort(addr); err != nil { 56 return fmt.Errorf("invalid tunnel target or address %s", addr) 57 } 58 } 59 60 *t = Tunnel(tunnel{ 61 Network: network, 62 Address: address, 63 Target: target, 64 }) 65 if len(parts) == 4 { 66 t.Proxy = parts[3] 67 } 68 return nil 69 }