mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-27 19:11:28 +00:00
149 lines
4.2 KiB
Go
149 lines
4.2 KiB
Go
|
package wireguard
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/base64"
|
||
|
"encoding/hex"
|
||
|
"net/netip"
|
||
|
|
||
|
"github.com/sagernet/sing-box/adapter"
|
||
|
"github.com/sagernet/sing-box/option"
|
||
|
dns "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
|
||
|
}
|