123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- package wireguard
- import (
- "context"
- "encoding/base64"
- "encoding/hex"
- "net/netip"
- "github.com/sagernet/sing-box/adapter"
- "github.com/sagernet/sing-box/option"
- "github.com/sagernet/sing-dns"
- E "github.com/sagernet/sing/common/exceptions"
- M "github.com/sagernet/sing/common/metadata"
- )
- type PeerConfig struct {
- destination M.Socksaddr
- domainStrategy dns.DomainStrategy
- Endpoint netip.AddrPort
- PublicKey string
- PreSharedKey string
- AllowedIPs []string
- Reserved [3]uint8
- }
- func (c PeerConfig) GenerateIpcLines() string {
- ipcLines := "\npublic_key=" + c.PublicKey
- ipcLines += "\nendpoint=" + c.Endpoint.String()
- if c.PreSharedKey != "" {
- ipcLines += "\npreshared_key=" + c.PreSharedKey
- }
- for _, allowedIP := range c.AllowedIPs {
- ipcLines += "\nallowed_ip=" + allowedIP
- }
- return ipcLines
- }
- func ParsePeers(options option.WireGuardOutboundOptions) ([]PeerConfig, error) {
- var peers []PeerConfig
- if len(options.Peers) > 0 {
- for peerIndex, rawPeer := range options.Peers {
- peer := PeerConfig{
- AllowedIPs: rawPeer.AllowedIPs,
- }
- destination := rawPeer.ServerOptions.Build()
- if destination.IsFqdn() {
- peer.destination = destination
- peer.domainStrategy = dns.DomainStrategy(options.DomainStrategy)
- } else {
- peer.Endpoint = destination.AddrPort()
- }
- {
- bytes, err := base64.StdEncoding.DecodeString(rawPeer.PublicKey)
- if err != nil {
- return nil, E.Cause(err, "decode public key for peer ", peerIndex)
- }
- peer.PublicKey = hex.EncodeToString(bytes)
- }
- if rawPeer.PreSharedKey != "" {
- bytes, err := base64.StdEncoding.DecodeString(rawPeer.PreSharedKey)
- if err != nil {
- return nil, E.Cause(err, "decode pre shared key for peer ", peerIndex)
- }
- peer.PreSharedKey = hex.EncodeToString(bytes)
- }
- if len(rawPeer.AllowedIPs) == 0 {
- return nil, E.New("missing allowed_ips for peer ", peerIndex)
- }
- if len(rawPeer.Reserved) > 0 {
- if len(rawPeer.Reserved) != 3 {
- return nil, E.New("invalid reserved value for peer ", peerIndex, ", required 3 bytes, got ", len(peer.Reserved))
- }
- copy(peer.Reserved[:], options.Reserved)
- }
- peers = append(peers, peer)
- }
- } else {
- peer := PeerConfig{}
- var (
- addressHas4 bool
- addressHas6 bool
- )
- for _, localAddress := range options.LocalAddress {
- if localAddress.Addr().Is4() {
- addressHas4 = true
- } else {
- addressHas6 = true
- }
- }
- if addressHas4 {
- peer.AllowedIPs = append(peer.AllowedIPs, netip.PrefixFrom(netip.IPv4Unspecified(), 0).String())
- }
- if addressHas6 {
- peer.AllowedIPs = append(peer.AllowedIPs, netip.PrefixFrom(netip.IPv6Unspecified(), 0).String())
- }
- destination := options.ServerOptions.Build()
- if destination.IsFqdn() {
- peer.destination = destination
- peer.domainStrategy = dns.DomainStrategy(options.DomainStrategy)
- } else {
- peer.Endpoint = destination.AddrPort()
- }
- {
- bytes, err := base64.StdEncoding.DecodeString(options.PeerPublicKey)
- if err != nil {
- return nil, E.Cause(err, "decode peer public key")
- }
- peer.PublicKey = hex.EncodeToString(bytes)
- }
- if options.PreSharedKey != "" {
- bytes, err := base64.StdEncoding.DecodeString(options.PreSharedKey)
- if err != nil {
- return nil, E.Cause(err, "decode pre shared key")
- }
- peer.PreSharedKey = hex.EncodeToString(bytes)
- }
- if len(options.Reserved) > 0 {
- if len(options.Reserved) != 3 {
- return nil, E.New("invalid reserved value, required 3 bytes, got ", len(peer.Reserved))
- }
- copy(peer.Reserved[:], options.Reserved)
- }
- peers = append(peers, peer)
- }
- return peers, nil
- }
- func ResolvePeers(ctx context.Context, router adapter.Router, peers []PeerConfig) error {
- for peerIndex, peer := range peers {
- if peer.Endpoint.IsValid() {
- continue
- }
- destinationAddresses, err := router.Lookup(ctx, peer.destination.Fqdn, peer.domainStrategy)
- if err != nil {
- if len(peers) == 1 {
- return E.Cause(err, "resolve endpoint domain")
- } else {
- return E.Cause(err, "resolve endpoint domain for peer ", peerIndex)
- }
- }
- if len(destinationAddresses) == 0 {
- return E.New("no addresses found for endpoint domain: ", peer.destination.Fqdn)
- }
- peers[peerIndex].Endpoint = netip.AddrPortFrom(destinationAddresses[0], peer.destination.Port)
- }
- return nil
- }
|