github.com/sagernet/sing-box@v1.9.0-rc.20/transport/wireguard/resolve.go (about)

     1  package wireguard
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"encoding/hex"
     7  	"net/netip"
     8  
     9  	"github.com/sagernet/sing-box/adapter"
    10  	"github.com/sagernet/sing-box/option"
    11  	dns "github.com/sagernet/sing-dns"
    12  	E "github.com/sagernet/sing/common/exceptions"
    13  	M "github.com/sagernet/sing/common/metadata"
    14  )
    15  
    16  type PeerConfig struct {
    17  	destination    M.Socksaddr
    18  	domainStrategy dns.DomainStrategy
    19  	Endpoint       netip.AddrPort
    20  	PublicKey      string
    21  	PreSharedKey   string
    22  	AllowedIPs     []string
    23  	Reserved       [3]uint8
    24  }
    25  
    26  func (c PeerConfig) GenerateIpcLines() string {
    27  	ipcLines := "\npublic_key=" + c.PublicKey
    28  	ipcLines += "\nendpoint=" + c.Endpoint.String()
    29  	if c.PreSharedKey != "" {
    30  		ipcLines += "\npreshared_key=" + c.PreSharedKey
    31  	}
    32  	for _, allowedIP := range c.AllowedIPs {
    33  		ipcLines += "\nallowed_ip=" + allowedIP
    34  	}
    35  	return ipcLines
    36  }
    37  
    38  func ParsePeers(options option.WireGuardOutboundOptions) ([]PeerConfig, error) {
    39  	var peers []PeerConfig
    40  	if len(options.Peers) > 0 {
    41  		for peerIndex, rawPeer := range options.Peers {
    42  			peer := PeerConfig{
    43  				AllowedIPs: rawPeer.AllowedIPs,
    44  			}
    45  			destination := rawPeer.ServerOptions.Build()
    46  			if destination.IsFqdn() {
    47  				peer.destination = destination
    48  				peer.domainStrategy = dns.DomainStrategy(options.DomainStrategy)
    49  			} else {
    50  				peer.Endpoint = destination.AddrPort()
    51  			}
    52  			{
    53  				bytes, err := base64.StdEncoding.DecodeString(rawPeer.PublicKey)
    54  				if err != nil {
    55  					return nil, E.Cause(err, "decode public key for peer ", peerIndex)
    56  				}
    57  				peer.PublicKey = hex.EncodeToString(bytes)
    58  			}
    59  			if rawPeer.PreSharedKey != "" {
    60  				bytes, err := base64.StdEncoding.DecodeString(rawPeer.PreSharedKey)
    61  				if err != nil {
    62  					return nil, E.Cause(err, "decode pre shared key for peer ", peerIndex)
    63  				}
    64  				peer.PreSharedKey = hex.EncodeToString(bytes)
    65  			}
    66  			if len(rawPeer.AllowedIPs) == 0 {
    67  				return nil, E.New("missing allowed_ips for peer ", peerIndex)
    68  			}
    69  			if len(rawPeer.Reserved) > 0 {
    70  				if len(rawPeer.Reserved) != 3 {
    71  					return nil, E.New("invalid reserved value for peer ", peerIndex, ", required 3 bytes, got ", len(peer.Reserved))
    72  				}
    73  				copy(peer.Reserved[:], options.Reserved)
    74  			}
    75  			peers = append(peers, peer)
    76  		}
    77  	} else {
    78  		peer := PeerConfig{}
    79  		var (
    80  			addressHas4 bool
    81  			addressHas6 bool
    82  		)
    83  		for _, localAddress := range options.LocalAddress {
    84  			if localAddress.Addr().Is4() {
    85  				addressHas4 = true
    86  			} else {
    87  				addressHas6 = true
    88  			}
    89  		}
    90  		if addressHas4 {
    91  			peer.AllowedIPs = append(peer.AllowedIPs, netip.PrefixFrom(netip.IPv4Unspecified(), 0).String())
    92  		}
    93  		if addressHas6 {
    94  			peer.AllowedIPs = append(peer.AllowedIPs, netip.PrefixFrom(netip.IPv6Unspecified(), 0).String())
    95  		}
    96  		destination := options.ServerOptions.Build()
    97  		if destination.IsFqdn() {
    98  			peer.destination = destination
    99  			peer.domainStrategy = dns.DomainStrategy(options.DomainStrategy)
   100  		} else {
   101  			peer.Endpoint = destination.AddrPort()
   102  		}
   103  		{
   104  			bytes, err := base64.StdEncoding.DecodeString(options.PeerPublicKey)
   105  			if err != nil {
   106  				return nil, E.Cause(err, "decode peer public key")
   107  			}
   108  			peer.PublicKey = hex.EncodeToString(bytes)
   109  		}
   110  		if options.PreSharedKey != "" {
   111  			bytes, err := base64.StdEncoding.DecodeString(options.PreSharedKey)
   112  			if err != nil {
   113  				return nil, E.Cause(err, "decode pre shared key")
   114  			}
   115  			peer.PreSharedKey = hex.EncodeToString(bytes)
   116  		}
   117  		if len(options.Reserved) > 0 {
   118  			if len(options.Reserved) != 3 {
   119  				return nil, E.New("invalid reserved value, required 3 bytes, got ", len(peer.Reserved))
   120  			}
   121  			copy(peer.Reserved[:], options.Reserved)
   122  		}
   123  		peers = append(peers, peer)
   124  	}
   125  	return peers, nil
   126  }
   127  
   128  func ResolvePeers(ctx context.Context, router adapter.Router, peers []PeerConfig) error {
   129  	for peerIndex, peer := range peers {
   130  		if peer.Endpoint.IsValid() {
   131  			continue
   132  		}
   133  		destinationAddresses, err := router.Lookup(ctx, peer.destination.Fqdn, peer.domainStrategy)
   134  		if err != nil {
   135  			if len(peers) == 1 {
   136  				return E.Cause(err, "resolve endpoint domain")
   137  			} else {
   138  				return E.Cause(err, "resolve endpoint domain for peer ", peerIndex)
   139  			}
   140  		}
   141  		if len(destinationAddresses) == 0 {
   142  			return E.New("no addresses found for endpoint domain: ", peer.destination.Fqdn)
   143  		}
   144  		peers[peerIndex].Endpoint = netip.AddrPortFrom(destinationAddresses[0], peer.destination.Port)
   145  
   146  	}
   147  	return nil
   148  }