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  }