github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/wgcfg/device_config.go (about) 1 /* 2 * Copyright (C) 2020 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package wgcfg 19 20 import ( 21 "encoding/base64" 22 "encoding/hex" 23 "encoding/json" 24 "fmt" 25 "net" 26 "strings" 27 "time" 28 29 "github.com/rs/zerolog/log" 30 ) 31 32 // Stats represents wireguard peer statistics information. 33 type Stats struct { 34 BytesSent uint64 `json:"bytes_sent"` 35 BytesReceived uint64 `json:"bytes_received"` 36 LastHandshake time.Time `json:"last_handshake"` 37 } 38 39 // DeviceConfig describes wireguard device configuration. 40 type DeviceConfig struct { 41 IfaceName string `json:"iface_name"` 42 MTU int `json:"mtu"` 43 Subnet net.IPNet `json:"subnet"` 44 PrivateKey string `json:"private_key"` 45 ListenPort int `json:"listen_port"` 46 DNSPort int `json:"dns_port,omitempty"` 47 DNS []string `json:"dns"` 48 // Used only for unix. 49 DNSScriptDir string `json:"dns_script_dir"` 50 51 Peer Peer `json:"peer"` 52 ReplacePeers bool `json:"replace_peers,omitempty"` 53 54 ProxyPort int `json:"proxy_port,omitempty"` 55 } 56 57 // MarshalJSON implements json.Marshaler interface to provide human readable configuration. 58 func (dc DeviceConfig) MarshalJSON() ([]byte, error) { 59 type peer struct { 60 PublicKey string `json:"public_key"` 61 Endpoint string `json:"endpoint"` 62 AllowedIPs []string `json:"allowed_i_ps"` 63 KeepAlivePeriodSeconds int `json:"keep_alive_period_seconds"` 64 } 65 66 type deviceConfig struct { 67 IfaceName string `json:"iface_name"` 68 Subnet string `json:"subnet"` 69 PrivateKey string `json:"private_key"` 70 ListenPort int `json:"listen_port"` 71 DNS []string `json:"dns"` 72 DNSScriptDir string `json:"dns_script_dir"` 73 Peer peer `json:"peer"` 74 ReplacePeers bool `json:"replace_peers,omitempty"` 75 ProxyPort int `json:"proxy_port,omitempty"` 76 } 77 78 var peerEndpoint string 79 if dc.Peer.Endpoint != nil { 80 peerEndpoint = dc.Peer.Endpoint.String() 81 } 82 83 return json.Marshal(&deviceConfig{ 84 IfaceName: dc.IfaceName, 85 Subnet: dc.Subnet.String(), 86 PrivateKey: dc.PrivateKey, 87 ListenPort: dc.ListenPort, 88 DNS: dc.DNS, 89 DNSScriptDir: dc.DNSScriptDir, 90 Peer: peer{ 91 PublicKey: dc.Peer.PublicKey, 92 Endpoint: peerEndpoint, 93 AllowedIPs: dc.Peer.AllowedIPs, 94 KeepAlivePeriodSeconds: dc.Peer.KeepAlivePeriodSeconds, 95 }, 96 ReplacePeers: dc.ReplacePeers, 97 ProxyPort: dc.ProxyPort, 98 }) 99 } 100 101 // UnmarshalJSON implements json.Unmarshaler interface to receive human readable configuration. 102 func (dc *DeviceConfig) UnmarshalJSON(data []byte) error { 103 type peer struct { 104 PublicKey string `json:"public_key"` 105 Endpoint string `json:"endpoint"` 106 AllowedIPs []string `json:"allowed_i_ps"` 107 KeepAlivePeriodSeconds int `json:"keep_alive_period_seconds"` 108 } 109 110 type deviceConfig struct { 111 IfaceName string `json:"iface_name"` 112 Subnet string `json:"subnet"` 113 PrivateKey string `json:"private_key"` 114 ListenPort int `json:"listen_port"` 115 DNS []string `json:"dns"` 116 DNSScriptDir string `json:"dns_script_dir"` 117 Peer peer `json:"peer"` 118 ReplacePeers bool `json:"replace_peers,omitempty"` 119 ProxyPort int `json:"proxy_port"` 120 } 121 122 cfg := deviceConfig{} 123 124 if err := json.Unmarshal(data, &cfg); err != nil { 125 return fmt.Errorf("could not unmarshal device config: %w", err) 126 } 127 128 ip, ipnet, err := net.ParseCIDR(cfg.Subnet) 129 if err != nil { 130 return fmt.Errorf("could not parse subnet: %w", err) 131 } 132 133 var peerEndpoint *net.UDPAddr 134 if cfg.Peer.Endpoint != "" { 135 peerEndpoint, err = net.ResolveUDPAddr("udp", cfg.Peer.Endpoint) 136 if err != nil { 137 return fmt.Errorf("could not resolve peer endpoint: %w", err) 138 } 139 } 140 141 dc.IfaceName = cfg.IfaceName 142 dc.Subnet = *ipnet 143 dc.Subnet.IP = ip 144 dc.PrivateKey = cfg.PrivateKey 145 dc.ListenPort = cfg.ListenPort 146 dc.DNS = cfg.DNS 147 dc.DNSScriptDir = cfg.DNSScriptDir 148 dc.Peer = Peer{ 149 PublicKey: cfg.Peer.PublicKey, 150 Endpoint: peerEndpoint, 151 AllowedIPs: cfg.Peer.AllowedIPs, 152 KeepAlivePeriodSeconds: cfg.Peer.KeepAlivePeriodSeconds, 153 } 154 dc.ReplacePeers = cfg.ReplacePeers 155 dc.ProxyPort = cfg.ProxyPort 156 157 return nil 158 } 159 160 // Encode encodes device config into string representation which is used for 161 // userspace and kernel space wireguard configuration. 162 func (dc *DeviceConfig) Encode() string { 163 var res strings.Builder 164 keyBytes, err := base64.StdEncoding.DecodeString(dc.PrivateKey) 165 if err != nil { 166 log.Err(err).Msg("Could not decode device private key. Will use empty config.") 167 return "" 168 } 169 hexKey := hex.EncodeToString(keyBytes) 170 171 res.WriteString(fmt.Sprintf("private_key=%s\n", hexKey)) 172 res.WriteString(fmt.Sprintf("listen_port=%d\n", dc.ListenPort)) 173 174 if dc.ReplacePeers { 175 res.WriteString(fmt.Sprintf("replace_peers=%t\n", dc.ReplacePeers)) 176 } 177 178 res.WriteString(dc.Peer.Encode()) 179 return res.String() 180 } 181 182 // Peer represents wireguard peer. 183 type Peer struct { 184 PublicKey string `json:"public_key"` 185 Endpoint *net.UDPAddr `json:"endpoint"` 186 AllowedIPs []string `json:"allowed_i_ps"` 187 KeepAlivePeriodSeconds int `json:"keep_alive_period_seconds"` 188 } 189 190 // Encode encodes device peer config into string representation which is used for 191 // userspace and kernel space wireguard configuration. 192 func (p *Peer) Encode() string { 193 var res strings.Builder 194 195 keyBytes, err := base64.StdEncoding.DecodeString(p.PublicKey) 196 if err != nil { 197 log.Err(err).Msg("Could not decode device public key. Will use empty config.") 198 return "" 199 } 200 hexKey := hex.EncodeToString(keyBytes) 201 res.WriteString(fmt.Sprintf("public_key=%s\n", hexKey)) 202 res.WriteString(fmt.Sprintf("persistent_keepalive_interval=%d\n", p.KeepAlivePeriodSeconds)) 203 if p.Endpoint != nil { 204 res.WriteString(fmt.Sprintf("endpoint=%s\n", p.Endpoint.String())) 205 } 206 for _, ip := range p.AllowedIPs { 207 res.WriteString(fmt.Sprintf("allowed_ip=%s\n", ip)) 208 } 209 return res.String() 210 }