got.go raw

   1  package state
   2  
   3  import (
   4  	"crypto/tls"
   5  	"errors"
   6  	"fmt"
   7  	"io/ioutil"
   8  	"math/rand"
   9  	"net"
  10  	"os"
  11  	"path/filepath"
  12  	"strconv"
  13  	"strings"
  14  	"time"
  15  
  16  	"github.com/btcsuite/go-socks/socks"
  17  	"github.com/p9c/p9/pkg/qu"
  18  	"go.uber.org/atomic"
  19  
  20  	"github.com/p9c/p9/pkg/log"
  21  	"github.com/p9c/p9/cmd/node/active"
  22  	"github.com/p9c/p9/pkg/amt"
  23  	"github.com/p9c/p9/pkg/apputil"
  24  	"github.com/p9c/p9/pkg/chaincfg"
  25  	"github.com/p9c/p9/pkg/chainrpc"
  26  	"github.com/p9c/p9/pkg/connmgr"
  27  	"github.com/p9c/p9/pkg/fork"
  28  	"github.com/p9c/p9/pkg/pipe"
  29  	"github.com/p9c/p9/pkg/util"
  30  	"github.com/p9c/p9/pkg/util/routeable"
  31  	"github.com/p9c/p9/pod/config"
  32  )
  33  
  34  // GetNew returns a fresh new context
  35  func GetNew(
  36  	config *config.Config, hf func(ifc interface{}) error,
  37  	quit qu.C,
  38  ) (s *State, e error) {
  39  	// after this, all the configurations are set and mostly sanitized
  40  	if e = config.Initialize(hf); E.Chk(e) {
  41  		// return
  42  		panic(e)
  43  	}
  44  	log.SetLogLevel(config.LogLevel.V())
  45  	chainClientReady := qu.T()
  46  	rand.Seed(time.Now().UnixNano())
  47  	rand.Seed(rand.Int63())
  48  	s = &State{
  49  		ChainClientReady: chainClientReady,
  50  		KillAll:          quit,
  51  		Config:           config,
  52  		ConfigMap:        config.Map,
  53  		StateCfg:         new(active.Config),
  54  		NodeChan:         make(chan *chainrpc.Server),
  55  		Syncing:          atomic.NewBool(true),
  56  	}
  57  	// everything in the configuration is set correctly up to this point, except for settings based on the running
  58  	// network, so after this is when those settings are elaborated
  59  	T.Ln("setting active network:", s.Config.Network.V())
  60  	switch s.Config.Network.V() {
  61  	case "testnet", "testnet3", "t":
  62  		s.ActiveNet = &chaincfg.TestNet3Params
  63  		fork.IsTestnet = true
  64  	case "regtestnet", "regressiontest", "r":
  65  		fork.IsTestnet = true
  66  		s.ActiveNet = &chaincfg.RegressionTestParams
  67  	case "simnet", "s":
  68  		fork.IsTestnet = true
  69  		s.ActiveNet = &chaincfg.SimNetParams
  70  	default:
  71  		if s.Config.Network.V() != "mainnet" &&
  72  			s.Config.Network.V() != "m" {
  73  			D.Ln("using mainnet for node")
  74  		}
  75  		s.ActiveNet = &chaincfg.MainNetParams
  76  	}
  77  	if (s.Config.LAN.True() || s.Config.Solo.True()) && s.ActiveNet.Name == "mainnet" {
  78  		if e = fmt.Errorf("neither Solo or LAN can be active on mainnet for obvious reasons"); F.Chk(e) {
  79  			return
  80  		}
  81  	}
  82  	// if pipe logging is enabled, start it up
  83  	if s.Config.PipeLog.True() {
  84  		D.Ln("starting up pipe logger")
  85  		pipe.LogServe(s.KillAll, fmt.Sprint(os.Args))
  86  	}
  87  	I.Ln("set to write logs in the network specific directory")
  88  	if e = s.Config.LogDir.Set(
  89  		filepath.Join(s.Config.DataDir.V(), s.ActiveNet.Name)); E.Chk(e) {
  90  	}
  91  	I.Ln("enable log file writing")
  92  	if e = log.SetLogWriteToFile(s.Config.LogDir.V(),
  93  		s.Config.RunningCommand.Name); E.Chk(e) {
  94  	}
  95  	// set up TLS stuff if it hasn't been set up yet. We assume if the configured values correspond to files the files
  96  	// are valid TLS cert/pairs, and that the key will be absent if onetimetlskey was set
  97  	if (s.Config.ClientTLS.True() || s.Config.ServerTLS.True()) &&
  98  		(
  99  			(!apputil.FileExists(s.Config.RPCKey.V()) && s.Config.OneTimeTLSKey.False()) ||
 100  				!apputil.FileExists(s.Config.RPCCert.V()) ||
 101  				!apputil.FileExists(s.Config.CAFile.V())) {
 102  		D.Ln("generating TLS certificates")
 103  		I.Ln(s.Config.RPCKey.V(), s.Config.RPCCert.V(), s.Config.RPCKey.V())
 104  		// Create directories for cert and key files if they do not yet exist.
 105  		certDir, _ := filepath.Split(s.Config.RPCCert.V())
 106  		keyDir, _ := filepath.Split(s.Config.RPCKey.V())
 107  		e = os.MkdirAll(certDir, 0700)
 108  		if e != nil {
 109  			E.Ln(e)
 110  			return
 111  		}
 112  		e = os.MkdirAll(keyDir, 0700)
 113  		if e != nil {
 114  			E.Ln(e)
 115  			return
 116  		}
 117  		// Generate cert pair.
 118  		org := "pod/wallet autogenerated cert"
 119  		validUntil := time.Now().Add(time.Hour * 24 * 365 * 10)
 120  		var cert, key []byte
 121  		cert, key, e = util.NewTLSCertPair(org, validUntil, nil)
 122  		if e != nil {
 123  			E.Ln(e)
 124  			return
 125  		}
 126  		_, e = tls.X509KeyPair(cert, key)
 127  		if e != nil {
 128  			E.Ln(e)
 129  			return
 130  		}
 131  		// Write cert and (potentially) the key files.
 132  		e = ioutil.WriteFile(s.Config.RPCCert.V(), cert, 0600)
 133  		if e != nil {
 134  			rmErr := os.Remove(s.Config.RPCCert.V())
 135  			if rmErr != nil {
 136  				E.Ln("cannot remove written certificates:", rmErr)
 137  			}
 138  			return
 139  		}
 140  		e = ioutil.WriteFile(s.Config.CAFile.V(), cert, 0600)
 141  		if e != nil {
 142  			rmErr := os.Remove(s.Config.RPCCert.V())
 143  			if rmErr != nil {
 144  				E.Ln("cannot remove written certificates:", rmErr)
 145  			}
 146  			return
 147  		}
 148  		e = ioutil.WriteFile(s.Config.RPCKey.V(), key, 0600)
 149  		if e != nil {
 150  			E.Ln(e)
 151  			rmErr := os.Remove(s.Config.RPCCert.V())
 152  			if rmErr != nil {
 153  				E.Ln("cannot remove written certificates:", rmErr)
 154  			}
 155  			rmErr = os.Remove(s.Config.CAFile.V())
 156  			if rmErr != nil {
 157  				E.Ln("cannot remove written certificates:", rmErr)
 158  			}
 159  			return
 160  		}
 161  		D.Ln("done generating TLS certificates")
 162  	}
 163  
 164  	// Validate profile port number
 165  	T.Ln("validating profile port number")
 166  	if s.Config.Profile.V() != "" {
 167  		var profilePort int
 168  		profilePort, e = strconv.Atoi(s.Config.Profile.V())
 169  		if e != nil || profilePort < 1024 || profilePort > 65535 {
 170  			e = fmt.Errorf("the profile port must be between 1024 and 65535, disabling profiling")
 171  			E.Ln(e)
 172  			return
 173  			// if e = s.Config.Profile.Set(""); E.Chk(e) {
 174  			// }
 175  		}
 176  	}
 177  
 178  	T.Ln("checking addpeer and connectpeer lists")
 179  	if s.Config.AddPeers.Len() > 0 && s.Config.ConnectPeers.Len() > 0 {
 180  		e = fmt.Errorf("the addpeers and connectpeers options can not be both set")
 181  		_, _ = fmt.Fprintln(os.Stderr, e)
 182  		return
 183  	}
 184  
 185  	T.Ln("checking proxy/connect for disabling listening")
 186  	if (s.Config.ProxyAddress.V() != "" || s.Config.ConnectPeers.Len() > 0) && s.Config.P2PListeners.Len() == 0 {
 187  		s.Config.DisableListen.T()
 188  	}
 189  
 190  	T.Ln("checking relay/reject nonstandard policy settings")
 191  	switch {
 192  	case s.Config.RelayNonStd.True() && s.Config.RejectNonStd.True():
 193  		e = fmt.Errorf("rejectnonstd and relaynonstd cannot be used together" +
 194  			" -- choose only one")
 195  		E.Ln(e)
 196  		return
 197  	}
 198  
 199  	// Chk to make sure limited and admin users don't have the same username
 200  	T.Ln("checking admin and limited username is different")
 201  	if !s.Config.Username.Empty() &&
 202  		s.Config.Username.V() == s.Config.LimitUser.V() {
 203  		e := fmt.Errorf("--username and --limituser must not specify the same username")
 204  		_, _ = fmt.Fprintln(os.Stderr, e)
 205  		os.Exit(1)
 206  	}
 207  	// Chk to make sure limited and admin users don't have the same password
 208  	T.Ln("checking limited and admin passwords are not the same")
 209  	if !s.Config.Password.Empty() &&
 210  		s.Config.Password.V() == s.Config.LimitPass.V() {
 211  		e := fmt.Errorf("password and limitpass must not specify the same password")
 212  		_, _ = fmt.Fprintln(os.Stderr, e)
 213  		os.Exit(1)
 214  	}
 215  
 216  	T.Ln("checking user agent comments", s.Config.UserAgentComments)
 217  	for _, uaComment := range s.Config.UserAgentComments.S() {
 218  		if strings.ContainsAny(uaComment, "/:()") {
 219  			e = fmt.Errorf(
 220  				"the following characters must not " +
 221  					"appear in user agent comments: '/', ':', '(', ')'",
 222  			)
 223  			_, _ = fmt.Fprintln(os.Stderr, e)
 224  			os.Exit(1)
 225  		}
 226  	}
 227  
 228  	T.Ln("checking min relay tx fee")
 229  	s.StateCfg.ActiveMinRelayTxFee, e = amt.NewAmount(s.Config.MinRelayTxFee.V())
 230  	if e != nil {
 231  		E.Ln(e)
 232  		str := "invalid minrelaytxfee: %v"
 233  		e = fmt.Errorf(str, e)
 234  		_, _ = fmt.Fprintln(os.Stderr, e)
 235  		os.Exit(0)
 236  	}
 237  	I.Ln("autolisten", s.Config.AutoListen.True())
 238  	// if autolisten is set, set default ports on all p2p listeners discovered to be available
 239  	if s.Config.AutoListen.True() {
 240  		I.Ln("autolisten is enabled")
 241  		_, allAddresses := routeable.GetAddressesAndInterfaces()
 242  		p2pAddresses := []string{}
 243  		for addr := range allAddresses {
 244  			p2pAddresses = append(p2pAddresses, net.JoinHostPort(addr, s.ActiveNet.DefaultPort))
 245  		}
 246  		if e = s.Config.P2PConnect.Set(p2pAddresses); E.Chk(e) {
 247  			return
 248  		}
 249  		if e = s.Config.P2PListeners.Set(p2pAddresses); E.Chk(e) {
 250  			return
 251  		}
 252  		s.StateCfg.Save = true
 253  	}
 254  
 255  	// if autoports is set, in addition, set all listeners to random automatic ports, this and autolisten can be
 256  	// combined for full auto, this enables multiple instances on one local host
 257  	var fP int
 258  	if s.Config.AutoPorts.True() {
 259  		I.Ln("autoports is enabled")
 260  		p2pl := [][]string{
 261  			s.Config.P2PListeners.V(), s.Config.RPCListeners.V(),
 262  			s.Config.WalletRPCListeners.V(),
 263  		}
 264  		for i := range p2pl {
 265  			for j := range p2pl[i] {
 266  				var h string
 267  				if h, _, e = net.SplitHostPort(p2pl[i][j]); E.Chk(e) {
 268  					return
 269  				}
 270  				if fP, e = GetFreePort(); E.Chk(e) {
 271  					return
 272  				}
 273  				addy := net.JoinHostPort(h, fmt.Sprint(fP))
 274  				p2pl[i][j] = addy
 275  			}
 276  		}
 277  		if e = s.Config.P2PListeners.Set(p2pl[0]); E.Chk(e) {
 278  			return
 279  		}
 280  		if e = s.Config.RPCListeners.Set(p2pl[1]); E.Chk(e) {
 281  			return
 282  		}
 283  		if e = s.Config.WalletRPCListeners.Set(p2pl[2]); E.Chk(e) {
 284  			return
 285  		}
 286  
 287  		s.StateCfg.Save = true
 288  	}
 289  	// if LAN or Solo are active, disable DNS seeding
 290  	if s.Config.LAN.True() || s.Config.Solo.True() {
 291  		W.Ln("disabling DNS seeding due to test mode settings active")
 292  		s.Config.DisableDNSSeed.T()
 293  	}
 294  
 295  	T.Ln("checking rpc server has a login enabled")
 296  	if (s.Config.Username.Empty() || s.Config.Password.Empty()) &&
 297  		(s.Config.LimitUser.Empty() || s.Config.LimitPass.Empty()) {
 298  		W.Ln("disabling RPC due to empty login credentials")
 299  		s.Config.DisableRPC.T()
 300  	}
 301  	T.Ln("checking rpc max concurrent requests")
 302  	if s.Config.RPCMaxConcurrentReqs.V() < 0 {
 303  		str := "The rpcmaxwebsocketconcurrentrequests opt may not be" +
 304  			" less than 0 -- parsed [%d]"
 305  		e = fmt.Errorf(str, s.Config.RPCMaxConcurrentReqs.V())
 306  		_, _ = fmt.Fprintln(os.Stderr, e)
 307  		// os.Exit(1)
 308  		return
 309  	}
 310  	// Setup dial and DNS resolution (lookup) functions depending on the specified
 311  	// options. The default is to use the standard net.DialTimeout function as well
 312  	// as the system DNS resolver. When a proxy is specified, the dial function is
 313  	// set to the proxy specific dial function and the lookup is set to use tor
 314  	// (unless --noonion is specified in which case the system DNS resolver is
 315  	// used).
 316  	T.Ln("setting network dialer and lookup")
 317  	s.StateCfg.Dial = net.DialTimeout
 318  	s.StateCfg.Lookup = net.LookupIP
 319  	if !s.Config.ProxyAddress.Empty() {
 320  		T.Ln("we are loading a proxy!")
 321  		_, _, e = net.SplitHostPort(s.Config.ProxyAddress.V())
 322  		if e != nil {
 323  			E.Ln(e)
 324  			str := "proxy address '%s' is invalid: %v"
 325  			e = fmt.Errorf(str, s.Config.ProxyAddress.V(), e)
 326  			fmt.Fprintln(os.Stderr, e)
 327  			// os.Exit(1)
 328  			return
 329  		}
 330  		// TODO: this is kinda stupid hm? switch *and* toggle by presence of flag value, one should be enough
 331  		if s.Config.OnionEnabled.True() && !s.Config.OnionProxyAddress.Empty() {
 332  			E.Ln("onion enabled but no onionproxy has been configured")
 333  			T.Ln("halting to avoid exposing IP address")
 334  		}
 335  		// Tor stream isolation requires either proxy or onion proxy to be set.
 336  		if s.Config.TorIsolation.True() &&
 337  			s.Config.ProxyAddress.Empty() &&
 338  			s.Config.OnionProxyAddress.Empty() {
 339  			e = fmt.Errorf("%s: Tor stream isolation requires either proxy or onionproxy to be set")
 340  			_, _ = fmt.Fprintln(os.Stderr, e)
 341  			return
 342  			// os.Exit(1)
 343  		}
 344  		if s.Config.OnionEnabled.False() {
 345  			if e = s.Config.OnionProxyAddress.Set(""); E.Chk(e) {
 346  			}
 347  		}
 348  
 349  		// Tor isolation flag means proxy credentials will be overridden unless there is
 350  		// also an onion proxy configured in which case that one will be overridden.
 351  		torIsolation := false
 352  		if s.Config.TorIsolation.True() && s.Config.OnionProxyAddress.Empty() &&
 353  			(!s.Config.ProxyUser.Empty() || !s.Config.ProxyPass.Empty()) {
 354  			torIsolation = true
 355  			W.Ln(
 356  				"Tor isolation set -- overriding specified" +
 357  					" proxy user credentials",
 358  			)
 359  		}
 360  		proxy := &socks.Proxy{
 361  			Addr:         s.Config.ProxyAddress.V(),
 362  			Username:     s.Config.ProxyUser.V(),
 363  			Password:     s.Config.ProxyPass.V(),
 364  			TorIsolation: torIsolation,
 365  		}
 366  		s.StateCfg.Dial = proxy.DialTimeout
 367  		// Treat the proxy as tor and perform DNS resolution through it unless the
 368  		// --noonion flag is set or there is an onion-specific proxy configured.
 369  		if s.Config.OnionEnabled.True() &&
 370  			s.Config.OnionProxyAddress.Empty() {
 371  			s.StateCfg.Lookup = func(host string) ([]net.IP, error) {
 372  				return connmgr.TorLookupIP(host, s.Config.ProxyAddress.V())
 373  			}
 374  		}
 375  	}
 376  	// Setup onion address dial function depending on the specified options. The
 377  	// default is to use the same dial function selected above. However, when an
 378  	// onion-specific proxy is specified, the onion address dial function is set to
 379  	// use the onion-specific proxy while leaving the normal dial function as
 380  	// selected above. This allows .onion address traffic to be routed through a
 381  	// different proxy than normal traffic.
 382  	T.Ln("setting up tor proxy if enabled")
 383  	if !s.Config.OnionProxyAddress.Empty() {
 384  		if _, _, e = net.SplitHostPort(s.Config.OnionProxyAddress.V()); E.Chk(e) {
 385  			e = fmt.Errorf("onion proxy address '%s' is invalid: %v",
 386  				s.Config.OnionProxyAddress.V(), e,
 387  			)
 388  			// _, _ = fmt.Fprintln(os.Stderr, e)
 389  		}
 390  		// Tor isolation flag means onion proxy credentials will be overridden.
 391  		if s.Config.TorIsolation.True() &&
 392  			(!s.Config.OnionProxyUser.Empty() || !s.Config.OnionProxyPass.Empty()) {
 393  			W.Ln(
 394  				"Tor isolation set - overriding specified onionproxy user" +
 395  					" credentials",
 396  			)
 397  		}
 398  	}
 399  	T.Ln("setting onion dialer")
 400  	s.StateCfg.Oniondial =
 401  		func(network, addr string, timeout time.Duration) (net.Conn, error) {
 402  			proxy := &socks.Proxy{
 403  				Addr:         s.Config.OnionProxyAddress.V(),
 404  				Username:     s.Config.OnionProxyUser.V(),
 405  				Password:     s.Config.OnionProxyPass.V(),
 406  				TorIsolation: s.Config.TorIsolation.True(),
 407  			}
 408  			return proxy.DialTimeout(network, addr, timeout)
 409  		}
 410  
 411  	// When configured in bridge mode (both --onion and --proxy are configured), it
 412  	// means that the proxy configured by --proxy is not a tor proxy, so override
 413  	// the DNS resolution to use the onion-specific proxy.
 414  	T.Ln("setting proxy lookup")
 415  	if !s.Config.ProxyAddress.Empty() {
 416  		s.StateCfg.Lookup = func(host string) ([]net.IP, error) {
 417  			return connmgr.TorLookupIP(host, s.Config.OnionProxyAddress.V())
 418  		}
 419  	} else {
 420  		s.StateCfg.Oniondial = s.StateCfg.Dial
 421  	}
 422  	// Specifying --noonion means the onion address dial function results in an error.
 423  	if s.Config.OnionEnabled.False() {
 424  		s.StateCfg.Oniondial = func(a, b string, t time.Duration) (
 425  			net.Conn, error,
 426  		) {
 427  			return nil, errors.New("tor has been disabled")
 428  		}
 429  	}
 430  	if s.StateCfg.Save || !apputil.FileExists(s.Config.ConfigFile.V()) {
 431  		s.StateCfg.Save = false
 432  		if s.Config.RunningCommand.Name == "kopach" {
 433  			return
 434  		}
 435  		D.Ln("saving configuration")
 436  		var e error
 437  		if e = s.Config.WriteToFile(s.Config.ConfigFile.V()); E.Chk(e) {
 438  		}
 439  	}
 440  	if s.ActiveNet.Name == chaincfg.TestNet3Params.Name {
 441  		fork.IsTestnet = true
 442  	}
 443  
 444  	return
 445  }
 446  
 447  // GetFreePort asks the kernel for free open ports that are ready to use.
 448  func GetFreePort() (int, error) {
 449  	var port int
 450  	addr, e := net.ResolveTCPAddr("tcp", "localhost:0")
 451  	if e != nil {
 452  		return 0, e
 453  	}
 454  	var l *net.TCPListener
 455  	l, e = net.ListenTCP("tcp", addr)
 456  	if e != nil {
 457  		return 0, e
 458  	}
 459  	defer func() {
 460  		if e := l.Close(); E.Chk(e) {
 461  		}
 462  	}()
 463  	port = l.Addr().(*net.TCPAddr).Port
 464  	return port, nil
 465  }
 466