config.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. Copyright © 2021-2022 Ettore Di Giacinto <[email protected]>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package config
  14. import (
  15. "fmt"
  16. "math/bits"
  17. "os"
  18. "runtime"
  19. "strings"
  20. "time"
  21. "github.com/ipfs/go-log"
  22. "github.com/libp2p/go-libp2p"
  23. dht "github.com/libp2p/go-libp2p-kad-dht"
  24. "github.com/libp2p/go-libp2p/core/network"
  25. "github.com/libp2p/go-libp2p/core/peer"
  26. "github.com/libp2p/go-libp2p/p2p/host/autorelay"
  27. rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
  28. mplex "github.com/libp2p/go-libp2p/p2p/muxer/mplex"
  29. yamux "github.com/libp2p/go-libp2p/p2p/muxer/yamux"
  30. connmanager "github.com/libp2p/go-libp2p/p2p/net/connmgr"
  31. "github.com/mudler/edgevpn/pkg/blockchain"
  32. "github.com/mudler/edgevpn/pkg/crypto"
  33. "github.com/mudler/edgevpn/pkg/discovery"
  34. "github.com/mudler/edgevpn/pkg/logger"
  35. "github.com/mudler/edgevpn/pkg/node"
  36. "github.com/mudler/edgevpn/pkg/trustzone"
  37. "github.com/mudler/edgevpn/pkg/trustzone/authprovider/ecdsa"
  38. "github.com/mudler/edgevpn/pkg/vpn"
  39. "github.com/mudler/water"
  40. "github.com/peterbourgon/diskv"
  41. )
  42. // Config is the config struct for the node and the default EdgeVPN services
  43. // It is used to generate opts for the node and the services before start.
  44. type Config struct {
  45. NetworkConfig, NetworkToken string
  46. Address string
  47. Router string
  48. Interface string
  49. Libp2pLogLevel, LogLevel string
  50. LowProfile, BootstrapIface bool
  51. Blacklist []string
  52. Concurrency int
  53. FrameTimeout string
  54. ChannelBufferSize, InterfaceMTU, PacketMTU int
  55. NAT NAT
  56. Connection Connection
  57. Discovery Discovery
  58. Ledger Ledger
  59. Limit ResourceLimit
  60. // PeerGuard (experimental)
  61. // enable peerguardian and add specific auth options
  62. PeerGuard PeerGuard
  63. }
  64. type PeerGuard struct {
  65. Enable bool
  66. Relaxed bool
  67. Autocleanup bool
  68. PeerGate bool
  69. // AuthProviders in the freemap form:
  70. // ecdsa:
  71. // private_key: "foo_bar"
  72. AuthProviders map[string]map[string]interface{}
  73. SyncInterval time.Duration
  74. }
  75. type ResourceLimit struct {
  76. FileLimit string
  77. LimitConfig *rcmgr.LimitConfig
  78. Scope string
  79. MaxConns int
  80. StaticMin int64
  81. StaticMax int64
  82. Enable bool
  83. }
  84. // Ledger is the ledger configuration structure
  85. type Ledger struct {
  86. AnnounceInterval, SyncInterval time.Duration
  87. StateDir string
  88. }
  89. // Discovery allows to enable/disable discovery and
  90. // set bootstrap peers
  91. type Discovery struct {
  92. DHT, MDNS bool
  93. BootstrapPeers []string
  94. Interval time.Duration
  95. }
  96. // Connection is the configuration section
  97. // relative to the connection services
  98. type Connection struct {
  99. HolePunch bool
  100. AutoRelay bool
  101. AutoRelayDiscoveryInterval time.Duration
  102. RelayV1 bool
  103. StaticRelays []string
  104. OnlyStaticRelays bool
  105. Mplex bool
  106. MaxConnections int
  107. }
  108. // NAT is the structure relative to NAT configuration settings
  109. // It allows to enable/disable the service and NAT mapping, and rate limiting too.
  110. type NAT struct {
  111. Service bool
  112. Map bool
  113. RateLimit bool
  114. RateLimitGlobal, RateLimitPeer int
  115. RateLimitInterval time.Duration
  116. }
  117. // Validate returns error if the configuration is not valid
  118. func (c Config) Validate() error {
  119. if c.NetworkConfig == "" &&
  120. c.NetworkToken == "" {
  121. return fmt.Errorf("EDGEVPNCONFIG or EDGEVPNTOKEN not supplied. At least a config file is required")
  122. }
  123. return nil
  124. }
  125. func peers2List(peers []string) discovery.AddrList {
  126. addrsList := discovery.AddrList{}
  127. for _, p := range peers {
  128. addrsList.Set(p)
  129. }
  130. return addrsList
  131. }
  132. func peers2AddrInfo(peers []string) []peer.AddrInfo {
  133. addrsList := []peer.AddrInfo{}
  134. for _, p := range peers {
  135. pi, err := peer.AddrInfoFromString(p)
  136. if err == nil {
  137. addrsList = append(addrsList, *pi)
  138. }
  139. }
  140. return addrsList
  141. }
  142. // ToOpts returns node and vpn options from a configuration
  143. func (c Config) ToOpts(l *logger.Logger) ([]node.Option, []vpn.Option, error) {
  144. if err := c.Validate(); err != nil {
  145. return nil, nil, err
  146. }
  147. config := c.NetworkConfig
  148. address := c.Address
  149. router := c.Router
  150. iface := c.Interface
  151. logLevel := c.LogLevel
  152. libp2plogLevel := c.Libp2pLogLevel
  153. dhtE, mDNS := c.Discovery.DHT, c.Discovery.MDNS
  154. ledgerState := c.Ledger.StateDir
  155. peers := c.Discovery.BootstrapPeers
  156. lvl, err := log.LevelFromString(logLevel)
  157. if err != nil {
  158. lvl = log.LevelError
  159. }
  160. llger := logger.New(lvl)
  161. libp2plvl, err := log.LevelFromString(libp2plogLevel)
  162. if err != nil {
  163. libp2plvl = log.LevelFatal
  164. }
  165. token := c.NetworkToken
  166. addrsList := peers2List(peers)
  167. dhtOpts := []dht.Option{}
  168. if c.LowProfile {
  169. dhtOpts = append(dhtOpts, dht.BucketSize(20))
  170. }
  171. d := discovery.NewDHT(dhtOpts...)
  172. m := &discovery.MDNS{}
  173. opts := []node.Option{
  174. node.WithDiscoveryInterval(c.Discovery.Interval),
  175. node.WithLedgerAnnounceTime(c.Ledger.AnnounceInterval),
  176. node.WithLedgerInterval(c.Ledger.SyncInterval),
  177. node.Logger(llger),
  178. node.WithDiscoveryBootstrapPeers(addrsList),
  179. node.WithBlacklist(c.Blacklist...),
  180. node.LibP2PLogLevel(libp2plvl),
  181. node.WithInterfaceAddress(address),
  182. node.WithSealer(&crypto.AESSealer{}),
  183. node.FromBase64(mDNS, dhtE, token, d, m),
  184. node.FromYaml(mDNS, dhtE, config, d, m),
  185. }
  186. vpnOpts := []vpn.Option{
  187. vpn.WithConcurrency(c.Concurrency),
  188. vpn.WithInterfaceAddress(address),
  189. vpn.WithLedgerAnnounceTime(c.Ledger.AnnounceInterval),
  190. vpn.Logger(llger),
  191. vpn.WithTimeout(c.FrameTimeout),
  192. vpn.WithInterfaceType(water.TUN),
  193. vpn.NetLinkBootstrap(c.BootstrapIface),
  194. vpn.WithChannelBufferSize(c.ChannelBufferSize),
  195. vpn.WithInterfaceMTU(c.InterfaceMTU),
  196. vpn.WithPacketMTU(c.PacketMTU),
  197. vpn.WithRouterAddress(router),
  198. vpn.WithInterfaceName(iface),
  199. }
  200. libp2pOpts := []libp2p.Option{libp2p.UserAgent("edgevpn")}
  201. // AutoRelay section configuration
  202. if c.Connection.AutoRelay {
  203. relayOpts := []autorelay.Option{}
  204. if c.Connection.RelayV1 {
  205. relayOpts = append(relayOpts, autorelay.WithCircuitV1Support())
  206. }
  207. staticRelays := c.Connection.StaticRelays
  208. if c.Connection.AutoRelayDiscoveryInterval == 0 {
  209. c.Connection.AutoRelayDiscoveryInterval = 5 * time.Minute
  210. }
  211. // If no relays are specified and no discovery interval, then just use default static relays (to be deprecated)
  212. relayOpts = append(relayOpts, autorelay.WithPeerSource(d.FindClosePeers(llger, c.Connection.OnlyStaticRelays, staticRelays...), c.Connection.AutoRelayDiscoveryInterval))
  213. libp2pOpts = append(libp2pOpts,
  214. libp2p.EnableAutoRelay(relayOpts...))
  215. }
  216. if c.Connection.Mplex {
  217. libp2pOpts = append(libp2pOpts,
  218. libp2p.ChainOptions(
  219. libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport),
  220. libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport),
  221. ))
  222. }
  223. if c.NAT.RateLimit {
  224. libp2pOpts = append(libp2pOpts, libp2p.AutoNATServiceRateLimit(
  225. c.NAT.RateLimitGlobal,
  226. c.NAT.RateLimitPeer,
  227. c.NAT.RateLimitInterval,
  228. ))
  229. }
  230. if c.Connection.MaxConnections != 0 {
  231. cm, err := connmanager.NewConnManager(
  232. 1,
  233. c.Connection.MaxConnections,
  234. connmanager.WithGracePeriod(80*time.Second),
  235. )
  236. if err != nil {
  237. llger.Fatal("could not create connection manager")
  238. }
  239. libp2pOpts = append(libp2pOpts, libp2p.ConnectionManager(cm))
  240. }
  241. if !c.Limit.Enable || runtime.GOOS == "darwin" {
  242. libp2pOpts = append(libp2pOpts, libp2p.ResourceManager(&network.NullResourceManager{}))
  243. } else {
  244. var limiter rcmgr.Limiter
  245. if c.Limit.FileLimit != "" {
  246. limitFile, err := os.Open(c.Limit.FileLimit)
  247. if err != nil {
  248. return opts, vpnOpts, err
  249. }
  250. defer limitFile.Close()
  251. l, err := rcmgr.NewDefaultLimiterFromJSON(limitFile)
  252. if err != nil {
  253. return opts, vpnOpts, err
  254. }
  255. limiter = l
  256. } else if c.Limit.MaxConns != 0 {
  257. min := int64(1 << 30)
  258. max := int64(4 << 30)
  259. if c.Limit.StaticMin != 0 {
  260. min = c.Limit.StaticMin
  261. }
  262. if c.Limit.StaticMax != 0 {
  263. max = c.Limit.StaticMax
  264. }
  265. maxconns := int(c.Limit.MaxConns)
  266. defaultLimits := rcmgr.DefaultLimits.Scale(min+max/2, logScale(2*maxconns))
  267. limiter = rcmgr.NewFixedLimiter(defaultLimits)
  268. } else {
  269. defaults := rcmgr.DefaultLimits
  270. def := &defaults
  271. libp2p.SetDefaultServiceLimits(def)
  272. limiter = rcmgr.NewFixedLimiter(def.AutoScale())
  273. }
  274. rc, err := rcmgr.NewResourceManager(limiter)
  275. if err != nil {
  276. llger.Fatal("could not create resource manager")
  277. }
  278. if c.Limit.LimitConfig != nil {
  279. if err := node.NetSetLimit(rc, c.Limit.Scope, &c.Limit.LimitConfig.System); err != nil {
  280. return opts, vpnOpts, err
  281. }
  282. }
  283. libp2pOpts = append(libp2pOpts, libp2p.ResourceManager(rc))
  284. }
  285. if c.Connection.HolePunch {
  286. libp2pOpts = append(libp2pOpts, libp2p.EnableHolePunching())
  287. }
  288. if c.NAT.Service {
  289. libp2pOpts = append(libp2pOpts, libp2p.EnableNATService())
  290. }
  291. if c.NAT.Map {
  292. libp2pOpts = append(libp2pOpts, libp2p.NATPortMap())
  293. }
  294. opts = append(opts, node.WithLibp2pOptions(libp2pOpts...))
  295. if ledgerState != "" {
  296. opts = append(opts, node.WithStore(blockchain.NewDiskStore(diskv.New(diskv.Options{
  297. BasePath: ledgerState,
  298. CacheSizeMax: uint64(50), // 50MB
  299. }))))
  300. } else {
  301. opts = append(opts, node.WithStore(&blockchain.MemoryStore{}))
  302. }
  303. if c.PeerGuard.Enable {
  304. pg := trustzone.NewPeerGater(c.PeerGuard.Relaxed)
  305. dur := c.PeerGuard.SyncInterval
  306. // Build up the authproviders for the peerguardian
  307. aps := []trustzone.AuthProvider{}
  308. for ap, providerOpts := range c.PeerGuard.AuthProviders {
  309. a, err := authProvider(llger, ap, providerOpts)
  310. if err != nil {
  311. return opts, vpnOpts, fmt.Errorf("invalid authprovider: %w", err)
  312. }
  313. aps = append(aps, a)
  314. }
  315. pguardian := trustzone.NewPeerGuardian(llger, aps...)
  316. opts = append(opts,
  317. node.WithNetworkService(
  318. pg.UpdaterService(dur),
  319. pguardian.Challenger(dur, c.PeerGuard.Autocleanup),
  320. ),
  321. node.EnableGenericHub,
  322. node.GenericChannelHandlers(pguardian.ReceiveMessage),
  323. )
  324. // We always pass a PeerGater such will be registered to the API if necessary
  325. opts = append(opts, node.WithPeerGater(pg))
  326. // IF it's not enabled, we just disable it right away.
  327. if !c.PeerGuard.PeerGate {
  328. pg.Disable()
  329. }
  330. }
  331. return opts, vpnOpts, nil
  332. }
  333. func authProvider(ll log.StandardLogger, s string, opts map[string]interface{}) (trustzone.AuthProvider, error) {
  334. switch strings.ToLower(s) {
  335. case "ecdsa":
  336. pk, exists := opts["private_key"]
  337. if !exists {
  338. return nil, fmt.Errorf("No private key provided")
  339. }
  340. return ecdsa.ECDSA521Provider(ll, fmt.Sprint(pk))
  341. }
  342. return nil, fmt.Errorf("not supported")
  343. }
  344. func logScale(val int) int {
  345. bitlen := bits.Len(uint(val))
  346. return 1 << bitlen
  347. }