github.com/lbryio/lbcd@v0.22.119/config.go (about) 1 // Copyright (c) 2013-2017 The btcsuite developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bufio" 9 "crypto/rand" 10 _ "embed" 11 "encoding/base64" 12 "encoding/hex" 13 "errors" 14 "fmt" 15 "io" 16 "net" 17 "os" 18 "path/filepath" 19 "runtime" 20 "sort" 21 "strconv" 22 "strings" 23 "time" 24 25 "github.com/btcsuite/go-socks/socks" 26 flags "github.com/jessevdk/go-flags" 27 "github.com/lbryio/lbcd/blockchain" 28 "github.com/lbryio/lbcd/chaincfg" 29 "github.com/lbryio/lbcd/chaincfg/chainhash" 30 "github.com/lbryio/lbcd/connmgr" 31 "github.com/lbryio/lbcd/database" 32 _ "github.com/lbryio/lbcd/database/ffldb" 33 "github.com/lbryio/lbcd/mempool" 34 "github.com/lbryio/lbcd/peer" 35 "github.com/lbryio/lbcd/version" 36 "github.com/lbryio/lbcd/wire" 37 btcutil "github.com/lbryio/lbcutil" 38 ) 39 40 const ( 41 defaultConfigFilename = "lbcd.conf" 42 defaultDataDirname = "data" 43 defaultLogLevel = "info" 44 defaultLogDirname = "logs" 45 defaultLogFilename = "lbcd.log" 46 defaultMaxPeers = 125 47 defaultBanDuration = time.Hour * 24 48 defaultBanThreshold = 100 49 defaultConnectTimeout = time.Second * 30 50 defaultMaxRPCClients = 10 51 defaultMaxRPCWebsockets = 25 52 defaultMaxRPCConcurrentReqs = 20 53 defaultDbType = "ffldb" 54 defaultFreeTxRelayLimit = 15.0 55 defaultTrickleInterval = peer.DefaultTrickleInterval 56 defaultBlockMinSize = 0 57 defaultBlockMaxSize = 750000 58 defaultBlockMinWeight = 0 59 defaultBlockMaxWeight = 3000000 60 blockMaxSizeMin = 1000 61 blockMaxSizeMax = blockchain.MaxBlockBaseSize - 1000 62 blockMaxWeightMin = 4000 63 blockMaxWeightMax = blockchain.MaxBlockWeight - 4000 64 defaultGenerate = false 65 defaultMaxOrphanTransactions = 100 66 defaultMaxOrphanTxSize = 100000 67 defaultSigCacheMaxSize = 100000 68 sampleConfigFilename = "sample-lbcd.conf" 69 defaultTxIndex = true 70 defaultAddrIndex = false 71 defaultUpnp = true 72 ) 73 74 var ( 75 defaultHomeDir = btcutil.AppDataDir("lbcd", false) 76 defaultConfigFile = filepath.Join(defaultHomeDir, defaultConfigFilename) 77 defaultDataDir = filepath.Join(defaultHomeDir, defaultDataDirname) 78 knownDbTypes = database.SupportedDrivers() 79 defaultRPCKeyFile = filepath.Join(defaultHomeDir, "rpc.key") 80 defaultRPCCertFile = filepath.Join(defaultHomeDir, "rpc.cert") 81 defaultLogDir = filepath.Join(defaultHomeDir, defaultLogDirname) 82 ) 83 84 //go:embed sample-lbcd.conf 85 var sampleConfig string 86 87 // runServiceCommand is only set to a real function on Windows. It is used 88 // to parse and execute service commands specified via the -s flag. 89 var runServiceCommand func(string) error 90 91 // minUint32 is a helper function to return the minimum of two uint32s. 92 // This avoids a math import and the need to cast to floats. 93 func minUint32(a, b uint32) uint32 { 94 if a < b { 95 return a 96 } 97 return b 98 } 99 100 // config defines the configuration options for btcd. 101 // 102 // See loadConfig for details on the configuration load process. 103 type config struct { 104 AddCheckpoints []string `long:"addcheckpoint" description:"Add a custom checkpoint. Format: '<height>:<hash>'"` 105 AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"` 106 AddrIndex bool `long:"addrindex" description:"Maintain a full address-based transaction index which makes the searchrawtransactions RPC available"` 107 AgentBlacklist []string `long:"agentblacklist" description:"A comma separated list of user-agent substrings which will cause lbcd to reject any peers whose user-agent contains any of the blacklisted substrings."` 108 AgentWhitelist []string `long:"agentwhitelist" description:"A comma separated list of user-agent substrings which will cause lbcd to require all peers' user-agents to contain one of the whitelisted substrings. The blacklist is applied before the whitelist, and an empty whitelist will allow all agents that do not fail the blacklist."` 109 BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"` 110 BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."` 111 BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"` 112 BlockMinSize uint32 `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"` 113 BlockMaxWeight uint32 `long:"blockmaxweight" description:"Maximum block weight to be used when creating a block"` 114 BlockMinWeight uint32 `long:"blockminweight" description:"Mininum block weight to be used when creating a block"` 115 BlockPrioritySize uint32 `long:"blockprioritysize" description:"Size in bytes for high-priority/low-fee transactions when creating a block"` 116 BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."` 117 ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"` 118 ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"` 119 CPUProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"` 120 MemProfile string `long:"memprofile" description:"Write memory profile to the specified file"` 121 DataDir string `short:"b" long:"datadir" description:"Directory to store data"` 122 DbType string `long:"dbtype" description:"Database backend to use for the Block Chain"` 123 DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"` 124 DropAddrIndex bool `long:"dropaddrindex" description:"Deletes the address-based transaction index from the database on start up and then exits."` 125 DropCfIndex bool `long:"dropcfindex" description:"Deletes the index used for committed filtering (CF) support from the database on start up and then exits."` 126 DropTxIndex bool `long:"droptxindex" description:"Deletes the hash-based transaction index from the database on start up and then exits."` 127 ExternalIPs []string `long:"externalip" description:"Add an ip to the list of local addresses we claim to listen on to peers"` 128 Generate bool `long:"generate" description:"Generate (mine) bitcoins using the CPU"` 129 FreeTxRelayLimit float64 `long:"limitfreerelay" description:"Limit relay of transactions with no transaction fee to the given amount in thousands of bytes per minute"` 130 Listeners []string `long:"listen" description:"Add an interface/port to listen for connections (default all interfaces port: 9246, testnet: 19246, regtest: 29246)"` 131 LogDir string `long:"logdir" description:"Directory to log output."` 132 MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"` 133 MaxPeers int `long:"maxpeers" description:"Max number of inbound and outbound peers"` 134 MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"` 135 MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in LBC/kB to be considered a non-zero fee."` 136 DisableBanning bool `long:"nobanning" description:"Disable banning of misbehaving peers"` 137 NoCFilters bool `long:"nocfilters" description:"Disable committed filtering (CF) support"` 138 DisableCheckpoints bool `long:"nocheckpoints" description:"Disable built-in checkpoints. Don't do this unless you know what you're doing."` 139 DisableDNSSeed bool `long:"nodnsseed" description:"Disable DNS seeding for peers"` 140 DisableListen bool `long:"nolisten" description:"Disable listening for incoming connections -- NOTE: Listening is automatically disabled if the --connect or --proxy options are used without also specifying listen interfaces via --listen"` 141 NoOnion bool `long:"noonion" description:"Disable connecting to tor hidden services"` 142 NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"` 143 NoRelayPriority bool `long:"norelaypriority" description:"Do not require free or low-fee transactions to have high priority for relaying"` 144 NoWinService bool `long:"nowinservice" description:"Do not start as a background service on Windows -- NOTE: This flag only works on the command line, not in the config file"` 145 DisableRPC bool `long:"norpc" description:"Disable built-in RPC server -- NOTE: The RPC server is disabled by default if no rpcuser/rpcpass or rpclimituser/rpclimitpass is specified"` 146 DisableStallHandler bool `long:"nostalldetect" description:"Disables the stall handler system for each peer, useful in simnet/regtest integration tests frameworks"` 147 DisableTLS bool `long:"notls" description:"Disable TLS for the RPC server -- NOTE: This is only allowed if the RPC server is bound to localhost"` 148 OnionProxy string `long:"onion" description:"Connect to tor hidden services via SOCKS5 proxy (eg. 127.0.0.1:9050)"` 149 OnionProxyPass string `long:"onionpass" default-mask:"-" description:"Password for onion proxy server"` 150 OnionProxyUser string `long:"onionuser" description:"Username for onion proxy server"` 151 Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"` 152 Proxy string `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"` 153 ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"` 154 ProxyUser string `long:"proxyuser" description:"Username for proxy server"` 155 RegressionTest bool `long:"regtest" description:"Use the regression test network"` 156 RejectNonStd bool `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."` 157 RejectReplacement bool `long:"rejectreplacement" description:"Reject transactions that attempt to replace existing transactions within the mempool through the Replace-By-Fee (RBF) signaling policy."` 158 RelayNonStd bool `long:"relaynonstd" description:"Relay non-standard transactions regardless of the default settings for the active network."` 159 RPCCert string `long:"rpccert" description:"File containing the certificate file"` 160 RPCKey string `long:"rpckey" description:"File containing the certificate key"` 161 RPCLimitPass string `long:"rpclimitpass" default-mask:"-" description:"Password for limited RPC connections"` 162 RPCLimitUser string `long:"rpclimituser" description:"Username for limited RPC connections"` 163 RPCListeners []string `long:"rpclisten" description:"Add an interface/port to listen for RPC connections (default port: 9245, testnet: 19245, regtest: 29245)"` 164 RPCMaxClients int `long:"rpcmaxclients" description:"Max number of RPC clients for standard connections"` 165 RPCMaxConcurrentReqs int `long:"rpcmaxconcurrentreqs" description:"Max number of concurrent RPC requests that may be processed concurrently"` 166 RPCMaxWebsockets int `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"` 167 RPCQuirks bool `long:"rpcquirks" description:"Mirror some JSON-RPC quirks of Bitcoin Core -- NOTE: Discouraged unless interoperability issues need to be worked around"` 168 RPCPass string `short:"P" long:"rpcpass" default-mask:"-" description:"Password for RPC connections"` 169 RPCUser string `short:"u" long:"rpcuser" description:"Username for RPC connections"` 170 SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"` 171 SimNet bool `long:"simnet" description:"Use the simulation test network"` 172 SigNet bool `long:"signet" description:"Use the signet test network"` 173 SigNetChallenge string `long:"signetchallenge" description:"Connect to a custom signet network defined by this challenge instead of using the global default signet test network -- Can be specified multiple times"` 174 SigNetSeedNode []string `long:"signetseednode" description:"Specify a seed node for the signet network instead of using the global default signet network seed nodes"` 175 TestNet3 bool `long:"testnet" description:"Use the test network"` 176 TorIsolation bool `long:"torisolation" description:"Enable Tor stream isolation by randomizing user credentials for each connection."` 177 TrickleInterval time.Duration `long:"trickleinterval" description:"Minimum time between attempts to send new inventory to a connected peer"` 178 TxIndex bool `long:"txindex" description:"Maintain a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"` 179 UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."` 180 Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"` 181 ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` 182 Whitelists []string `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"` 183 lookup func(string) ([]net.IP, error) 184 oniondial func(string, string, time.Duration) (net.Conn, error) 185 dial func(string, string, time.Duration) (net.Conn, error) 186 addCheckpoints []chaincfg.Checkpoint 187 miningAddrs []btcutil.Address 188 minRelayTxFee btcutil.Amount 189 whitelists []*net.IPNet 190 } 191 192 // serviceOptions defines the configuration options for the daemon as a service on 193 // Windows. 194 type serviceOptions struct { 195 ServiceCommand string `short:"s" long:"service" description:"Service command {install, remove, start, stop}"` 196 } 197 198 // cleanAndExpandPath expands environment variables and leading ~ in the 199 // passed path, cleans the result, and returns it. 200 func cleanAndExpandPath(path string) string { 201 // Expand initial ~ to OS specific home directory. 202 if strings.HasPrefix(path, "~") { 203 homeDir := filepath.Dir(defaultHomeDir) 204 path = strings.Replace(path, "~", homeDir, 1) 205 } 206 207 // NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%, 208 // but they variables can still be expanded via POSIX-style $VARIABLE. 209 return filepath.Clean(os.ExpandEnv(path)) 210 } 211 212 // validLogLevel returns whether or not logLevel is a valid debug log level. 213 func validLogLevel(logLevel string) bool { 214 switch logLevel { 215 case "trace": 216 fallthrough 217 case "debug": 218 fallthrough 219 case "info": 220 fallthrough 221 case "warn": 222 fallthrough 223 case "error": 224 fallthrough 225 case "critical": 226 return true 227 } 228 return false 229 } 230 231 // supportedSubsystems returns a sorted slice of the supported subsystems for 232 // logging purposes. 233 func supportedSubsystems() []string { 234 // Convert the subsystemLoggers map keys to a slice. 235 subsystems := make([]string, 0, len(subsystemLoggers)) 236 for subsysID := range subsystemLoggers { 237 subsystems = append(subsystems, subsysID) 238 } 239 240 // Sort the subsystems for stable display. 241 sort.Strings(subsystems) 242 return subsystems 243 } 244 245 // parseAndSetDebugLevels attempts to parse the specified debug level and set 246 // the levels accordingly. An appropriate error is returned if anything is 247 // invalid. 248 func parseAndSetDebugLevels(debugLevel string) error { 249 // When the specified string doesn't have any delimters, treat it as 250 // the log level for all subsystems. 251 if !strings.Contains(debugLevel, ",") && !strings.Contains(debugLevel, "=") { 252 // Validate debug log level. 253 if !validLogLevel(debugLevel) { 254 str := "The specified debug level [%v] is invalid" 255 return fmt.Errorf(str, debugLevel) 256 } 257 258 // Change the logging level for all subsystems. 259 setLogLevels(debugLevel) 260 261 return nil 262 } 263 264 // Split the specified string into subsystem/level pairs while detecting 265 // issues and update the log levels accordingly. 266 for _, logLevelPair := range strings.Split(debugLevel, ",") { 267 if !strings.Contains(logLevelPair, "=") { 268 str := "The specified debug level contains an invalid " + 269 "subsystem/level pair [%v]" 270 return fmt.Errorf(str, logLevelPair) 271 } 272 273 // Extract the specified subsystem and log level. 274 fields := strings.Split(logLevelPair, "=") 275 subsysID, logLevel := fields[0], fields[1] 276 277 // Validate subsystem. 278 if _, exists := subsystemLoggers[subsysID]; !exists { 279 str := "The specified subsystem [%v] is invalid -- " + 280 "supported subsytems %v" 281 return fmt.Errorf(str, subsysID, supportedSubsystems()) 282 } 283 284 // Validate log level. 285 if !validLogLevel(logLevel) { 286 str := "The specified debug level [%v] is invalid" 287 return fmt.Errorf(str, logLevel) 288 } 289 290 setLogLevel(subsysID, logLevel) 291 } 292 293 return nil 294 } 295 296 // validDbType returns whether or not dbType is a supported database type. 297 func validDbType(dbType string) bool { 298 for _, knownType := range knownDbTypes { 299 if dbType == knownType { 300 return true 301 } 302 } 303 304 return false 305 } 306 307 // removeDuplicateAddresses returns a new slice with all duplicate entries in 308 // addrs removed. 309 func removeDuplicateAddresses(addrs []string) []string { 310 result := make([]string, 0, len(addrs)) 311 seen := map[string]struct{}{} 312 for _, val := range addrs { 313 if _, ok := seen[val]; !ok { 314 result = append(result, val) 315 seen[val] = struct{}{} 316 } 317 } 318 return result 319 } 320 321 // normalizeAddress returns addr with the passed default port appended if 322 // there is not already a port specified. 323 func normalizeAddress(addr, defaultPort string) string { 324 _, _, err := net.SplitHostPort(addr) 325 if err != nil { 326 return net.JoinHostPort(addr, defaultPort) 327 } 328 return addr 329 } 330 331 // normalizeAddresses returns a new slice with all the passed peer addresses 332 // normalized with the given default port, and all duplicates removed. 333 func normalizeAddresses(addrs []string, defaultPort string) []string { 334 for i, addr := range addrs { 335 addrs[i] = normalizeAddress(addr, defaultPort) 336 } 337 338 return removeDuplicateAddresses(addrs) 339 } 340 341 // newCheckpointFromStr parses checkpoints in the '<height>:<hash>' format. 342 func newCheckpointFromStr(checkpoint string) (chaincfg.Checkpoint, error) { 343 parts := strings.Split(checkpoint, ":") 344 if len(parts) != 2 { 345 return chaincfg.Checkpoint{}, fmt.Errorf("unable to parse "+ 346 "checkpoint %q -- use the syntax <height>:<hash>", 347 checkpoint) 348 } 349 350 height, err := strconv.ParseInt(parts[0], 10, 32) 351 if err != nil { 352 return chaincfg.Checkpoint{}, fmt.Errorf("unable to parse "+ 353 "checkpoint %q due to malformed height", checkpoint) 354 } 355 356 if len(parts[1]) == 0 { 357 return chaincfg.Checkpoint{}, fmt.Errorf("unable to parse "+ 358 "checkpoint %q due to missing hash", checkpoint) 359 } 360 hash, err := chainhash.NewHashFromStr(parts[1]) 361 if err != nil { 362 return chaincfg.Checkpoint{}, fmt.Errorf("unable to parse "+ 363 "checkpoint %q due to malformed hash", checkpoint) 364 } 365 366 return chaincfg.Checkpoint{ 367 Height: int32(height), 368 Hash: hash, 369 }, nil 370 } 371 372 // parseCheckpoints checks the checkpoint strings for valid syntax 373 // ('<height>:<hash>') and parses them to chaincfg.Checkpoint instances. 374 func parseCheckpoints(checkpointStrings []string) ([]chaincfg.Checkpoint, error) { 375 if len(checkpointStrings) == 0 { 376 return nil, nil 377 } 378 checkpoints := make([]chaincfg.Checkpoint, len(checkpointStrings)) 379 for i, cpString := range checkpointStrings { 380 checkpoint, err := newCheckpointFromStr(cpString) 381 if err != nil { 382 return nil, err 383 } 384 checkpoints[i] = checkpoint 385 } 386 return checkpoints, nil 387 } 388 389 // filesExists reports whether the named file or directory exists. 390 func fileExists(name string) bool { 391 if _, err := os.Stat(name); err != nil { 392 if os.IsNotExist(err) { 393 return false 394 } 395 } 396 return true 397 } 398 399 // newConfigParser returns a new command line flags parser. 400 func newConfigParser(cfg *config, so *serviceOptions, options flags.Options) *flags.Parser { 401 parser := flags.NewParser(cfg, options) 402 if runtime.GOOS == "windows" { 403 parser.AddGroup("Service Options", "Service Options", so) 404 } 405 return parser 406 } 407 408 // loadConfig initializes and parses the config using a config file and command 409 // line options. 410 // 411 // The configuration proceeds as follows: 412 // 1. Start with a default config with sane settings 413 // 2. Pre-parse the command line to check for an alternative config file 414 // 3. Load configuration file overwriting defaults with any specified options 415 // 4. Parse CLI options and overwrite/add any specified options 416 // 417 // The above results in lbcd functioning properly without any config settings 418 // while still allowing the user to override settings with config files and 419 // command line options. Command line options always take precedence. 420 func loadConfig() (*config, []string, error) { 421 // Default config. 422 cfg := config{ 423 ConfigFile: defaultConfigFile, 424 DebugLevel: defaultLogLevel, 425 MaxPeers: defaultMaxPeers, 426 BanDuration: defaultBanDuration, 427 BanThreshold: defaultBanThreshold, 428 RPCMaxClients: defaultMaxRPCClients, 429 RPCMaxWebsockets: defaultMaxRPCWebsockets, 430 RPCMaxConcurrentReqs: defaultMaxRPCConcurrentReqs, 431 DataDir: defaultDataDir, 432 LogDir: defaultLogDir, 433 DbType: defaultDbType, 434 RPCKey: defaultRPCKeyFile, 435 RPCCert: defaultRPCCertFile, 436 MinRelayTxFee: mempool.DefaultMinRelayTxFee.ToBTC(), 437 FreeTxRelayLimit: defaultFreeTxRelayLimit, 438 TrickleInterval: defaultTrickleInterval, 439 BlockMinSize: defaultBlockMinSize, 440 BlockMaxSize: defaultBlockMaxSize, 441 BlockMinWeight: defaultBlockMinWeight, 442 BlockMaxWeight: defaultBlockMaxWeight, 443 BlockPrioritySize: mempool.DefaultBlockPrioritySize, 444 MaxOrphanTxs: defaultMaxOrphanTransactions, 445 SigCacheMaxSize: defaultSigCacheMaxSize, 446 Generate: defaultGenerate, 447 TxIndex: defaultTxIndex, 448 AddrIndex: defaultAddrIndex, 449 Upnp: defaultUpnp, 450 } 451 452 // Service options which are only added on Windows. 453 serviceOpts := serviceOptions{} 454 455 // Pre-parse the command line options to see if an alternative config 456 // file or the version flag was specified. Any errors aside from the 457 // help message error can be ignored here since they will be caught by 458 // the final parse below. 459 preCfg := cfg 460 preParser := newConfigParser(&preCfg, &serviceOpts, flags.HelpFlag) 461 _, err := preParser.Parse() 462 if err != nil { 463 if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp { 464 fmt.Fprintln(os.Stderr, err) 465 return nil, nil, err 466 } 467 } 468 469 // Show the version and exit if the version flag was specified. 470 appName := filepath.Base(os.Args[0]) 471 appName = strings.TrimSuffix(appName, filepath.Ext(appName)) 472 usageMessage := fmt.Sprintf("Use %s -h to show usage", appName) 473 if preCfg.ShowVersion { 474 fmt.Println(appName, "version", version.Full()) 475 os.Exit(0) 476 } 477 478 // Perform service command and exit if specified. Invalid service 479 // commands show an appropriate error. Only runs on Windows since 480 // the runServiceCommand function will be nil when not on Windows. 481 if serviceOpts.ServiceCommand != "" && runServiceCommand != nil { 482 err := runServiceCommand(serviceOpts.ServiceCommand) 483 if err != nil { 484 fmt.Fprintln(os.Stderr, err) 485 } 486 os.Exit(0) 487 } 488 489 // Load additional config from file. 490 var configFileError error 491 parser := newConfigParser(&cfg, &serviceOpts, flags.Default) 492 if !(preCfg.RegressionTest || preCfg.SimNet || preCfg.SigNet) || 493 preCfg.ConfigFile != defaultConfigFile { 494 495 if _, err := os.Stat(preCfg.ConfigFile); os.IsNotExist(err) { 496 err := createDefaultConfigFile(preCfg.ConfigFile) 497 if err != nil { 498 fmt.Fprintf(os.Stderr, "Error creating a "+ 499 "default config file: %v\n", err) 500 } 501 } 502 503 err := flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile) 504 if err != nil { 505 if _, ok := err.(*os.PathError); !ok { 506 fmt.Fprintf(os.Stderr, "Error parsing config "+ 507 "file: %v\n", err) 508 fmt.Fprintln(os.Stderr, usageMessage) 509 return nil, nil, err 510 } 511 configFileError = err 512 } 513 } 514 515 // Don't add peers from the config file when in regression test mode. 516 if preCfg.RegressionTest && len(cfg.AddPeers) > 0 { 517 cfg.AddPeers = nil 518 } 519 520 // Parse command line options again to ensure they take precedence. 521 remainingArgs, err := parser.Parse() 522 if err != nil { 523 if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp { 524 fmt.Fprintln(os.Stderr, usageMessage) 525 } 526 return nil, nil, err 527 } 528 529 // Create the home directory if it doesn't already exist. 530 funcName := "loadConfig" 531 err = os.MkdirAll(defaultHomeDir, 0700) 532 if err != nil { 533 // Show a nicer error message if it's because a symlink is 534 // linked to a directory that does not exist (probably because 535 // it's not mounted). 536 if e, ok := err.(*os.PathError); ok && os.IsExist(err) { 537 if link, lerr := os.Readlink(e.Path); lerr == nil { 538 str := "is symlink %s -> %s mounted?" 539 err = fmt.Errorf(str, e.Path, link) 540 } 541 } 542 543 str := "%s: Failed to create home directory: %v" 544 err := fmt.Errorf(str, funcName, err) 545 fmt.Fprintln(os.Stderr, err) 546 return nil, nil, err 547 } 548 549 // Multiple networks can't be selected simultaneously. 550 numNets := 0 551 // Count number of network flags passed; assign active network params 552 // while we're at it 553 if cfg.TestNet3 { 554 numNets++ 555 activeNetParams = &testNet3Params 556 } 557 if cfg.RegressionTest { 558 numNets++ 559 activeNetParams = ®ressionNetParams 560 } 561 if cfg.SimNet { 562 numNets++ 563 // Also disable dns seeding on the simulation test network. 564 activeNetParams = &simNetParams 565 cfg.DisableDNSSeed = true 566 } 567 if cfg.SigNet { 568 numNets++ 569 activeNetParams = &sigNetParams 570 571 // Let the user overwrite the default signet parameters. The 572 // challenge defines the actual signet network to join and the 573 // seed nodes are needed for network discovery. 574 sigNetChallenge := chaincfg.DefaultSignetChallenge 575 sigNetSeeds := chaincfg.DefaultSignetDNSSeeds 576 if cfg.SigNetChallenge != "" { 577 challenge, err := hex.DecodeString(cfg.SigNetChallenge) 578 if err != nil { 579 str := "%s: Invalid signet challenge, hex " + 580 "decode failed: %v" 581 err := fmt.Errorf(str, funcName, err) 582 fmt.Fprintln(os.Stderr, err) 583 fmt.Fprintln(os.Stderr, usageMessage) 584 return nil, nil, err 585 } 586 sigNetChallenge = challenge 587 } 588 589 if len(cfg.SigNetSeedNode) > 0 { 590 sigNetSeeds = make( 591 []chaincfg.DNSSeed, len(cfg.SigNetSeedNode), 592 ) 593 for idx, seed := range cfg.SigNetSeedNode { 594 sigNetSeeds[idx] = chaincfg.DNSSeed{ 595 Host: seed, 596 HasFiltering: false, 597 } 598 } 599 } 600 601 chainParams := chaincfg.CustomSignetParams( 602 sigNetChallenge, sigNetSeeds, 603 ) 604 activeNetParams.Params = &chainParams 605 } 606 if numNets > 1 { 607 str := "%s: The testnet, regtest, segnet, signet and simnet " + 608 "params can't be used together -- choose one of the " + 609 "five" 610 err := fmt.Errorf(str, funcName) 611 fmt.Fprintln(os.Stderr, err) 612 fmt.Fprintln(os.Stderr, usageMessage) 613 return nil, nil, err 614 } 615 616 // If mainnet is active, then we won't allow the stall handler to be 617 // disabled. 618 if activeNetParams.Params.Net == wire.MainNet && cfg.DisableStallHandler { 619 str := "%s: stall handler cannot be disabled on mainnet" 620 err := fmt.Errorf(str, funcName) 621 fmt.Fprintln(os.Stderr, err) 622 fmt.Fprintln(os.Stderr, usageMessage) 623 return nil, nil, err 624 } 625 626 // Set the default policy for relaying non-standard transactions 627 // according to the default of the active network. The set 628 // configuration value takes precedence over the default value for the 629 // selected network. 630 relayNonStd := activeNetParams.RelayNonStdTxs 631 switch { 632 case cfg.RelayNonStd && cfg.RejectNonStd: 633 str := "%s: rejectnonstd and relaynonstd cannot be used " + 634 "together -- choose only one" 635 err := fmt.Errorf(str, funcName) 636 fmt.Fprintln(os.Stderr, err) 637 fmt.Fprintln(os.Stderr, usageMessage) 638 return nil, nil, err 639 case cfg.RejectNonStd: 640 relayNonStd = false 641 case cfg.RelayNonStd: 642 relayNonStd = true 643 } 644 cfg.RelayNonStd = relayNonStd 645 646 // Append the network type to the data directory so it is "namespaced" 647 // per network. In addition to the block database, there are other 648 // pieces of data that are saved to disk such as address manager state. 649 // All data is specific to a network, so namespacing the data directory 650 // means each individual piece of serialized data does not have to 651 // worry about changing names per network and such. 652 cfg.DataDir = cleanAndExpandPath(cfg.DataDir) 653 cfg.DataDir = filepath.Join(cfg.DataDir, netName(activeNetParams)) 654 655 // Append the network type to the log directory so it is "namespaced" 656 // per network in the same fashion as the data directory. 657 cfg.LogDir = cleanAndExpandPath(cfg.LogDir) 658 cfg.LogDir = filepath.Join(cfg.LogDir, netName(activeNetParams)) 659 660 // Special show command to list supported subsystems and exit. 661 if cfg.DebugLevel == "show" { 662 fmt.Println("Supported subsystems", supportedSubsystems()) 663 os.Exit(0) 664 } 665 666 // Initialize log rotation. After log rotation has been initialized, the 667 // logger variables may be used. 668 initLogRotator(filepath.Join(cfg.LogDir, defaultLogFilename)) 669 670 // Parse, validate, and set debug log level(s). 671 if err := parseAndSetDebugLevels(cfg.DebugLevel); err != nil { 672 err := fmt.Errorf("%s: %v", funcName, err.Error()) 673 fmt.Fprintln(os.Stderr, err) 674 fmt.Fprintln(os.Stderr, usageMessage) 675 return nil, nil, err 676 } 677 678 // Validate database type. 679 if !validDbType(cfg.DbType) { 680 str := "%s: The specified database type [%v] is invalid -- " + 681 "supported types %v" 682 err := fmt.Errorf(str, funcName, cfg.DbType, knownDbTypes) 683 fmt.Fprintln(os.Stderr, err) 684 fmt.Fprintln(os.Stderr, usageMessage) 685 return nil, nil, err 686 } 687 688 // Validate profile port number 689 if cfg.Profile != "" { 690 profilePort, err := strconv.Atoi(cfg.Profile) 691 if err != nil || profilePort < 1024 || profilePort > 65535 { 692 str := "%s: The profile port must be between 1024 and 65535" 693 err := fmt.Errorf(str, funcName) 694 fmt.Fprintln(os.Stderr, err) 695 fmt.Fprintln(os.Stderr, usageMessage) 696 return nil, nil, err 697 } 698 } 699 700 // Don't allow ban durations that are too short. 701 if cfg.BanDuration < time.Second { 702 str := "%s: The banduration option may not be less than 1s -- parsed [%v]" 703 err := fmt.Errorf(str, funcName, cfg.BanDuration) 704 fmt.Fprintln(os.Stderr, err) 705 fmt.Fprintln(os.Stderr, usageMessage) 706 return nil, nil, err 707 } 708 709 // Validate any given whitelisted IP addresses and networks. 710 if len(cfg.Whitelists) > 0 { 711 var ip net.IP 712 cfg.whitelists = make([]*net.IPNet, 0, len(cfg.Whitelists)) 713 714 for _, addr := range cfg.Whitelists { 715 _, ipnet, err := net.ParseCIDR(addr) 716 if err != nil { 717 ip = net.ParseIP(addr) 718 if ip == nil { 719 str := "%s: The whitelist value of '%s' is invalid" 720 err = fmt.Errorf(str, funcName, addr) 721 fmt.Fprintln(os.Stderr, err) 722 fmt.Fprintln(os.Stderr, usageMessage) 723 return nil, nil, err 724 } 725 var bits int 726 if ip.To4() == nil { 727 // IPv6 728 bits = 128 729 } else { 730 bits = 32 731 } 732 ipnet = &net.IPNet{ 733 IP: ip, 734 Mask: net.CIDRMask(bits, bits), 735 } 736 } 737 cfg.whitelists = append(cfg.whitelists, ipnet) 738 } 739 } 740 741 // --addPeer and --connect do not mix. 742 if len(cfg.AddPeers) > 0 && len(cfg.ConnectPeers) > 0 { 743 str := "%s: the --addpeer and --connect options can not be " + 744 "mixed" 745 err := fmt.Errorf(str, funcName) 746 fmt.Fprintln(os.Stderr, err) 747 fmt.Fprintln(os.Stderr, usageMessage) 748 return nil, nil, err 749 } 750 751 // --proxy or --connect without --listen disables listening. 752 if (cfg.Proxy != "" || len(cfg.ConnectPeers) > 0) && 753 len(cfg.Listeners) == 0 { 754 cfg.DisableListen = true 755 } 756 757 // Connect means no DNS seeding. 758 if len(cfg.ConnectPeers) > 0 { 759 cfg.DisableDNSSeed = true 760 } 761 762 // Add the default listener if none were specified. The default 763 // listener is all addresses on the listen port for the network 764 // we are to connect to. 765 if len(cfg.Listeners) == 0 { 766 cfg.Listeners = []string{ 767 net.JoinHostPort("", activeNetParams.DefaultPort), 768 } 769 } 770 771 // Check to make sure limited and admin users don't have the same username 772 if cfg.RPCUser == cfg.RPCLimitUser && cfg.RPCUser != "" { 773 str := "%s: --rpcuser and --rpclimituser must not specify the " + 774 "same username" 775 err := fmt.Errorf(str, funcName) 776 fmt.Fprintln(os.Stderr, err) 777 fmt.Fprintln(os.Stderr, usageMessage) 778 return nil, nil, err 779 } 780 781 // Check to make sure limited and admin users don't have the same password 782 if cfg.RPCPass == cfg.RPCLimitPass && cfg.RPCPass != "" { 783 str := "%s: --rpcpass and --rpclimitpass must not specify the " + 784 "same password" 785 err := fmt.Errorf(str, funcName) 786 fmt.Fprintln(os.Stderr, err) 787 fmt.Fprintln(os.Stderr, usageMessage) 788 return nil, nil, err 789 } 790 791 // The RPC server is disabled if no username or password is provided. 792 if (cfg.RPCUser == "" || cfg.RPCPass == "") && 793 (cfg.RPCLimitUser == "" || cfg.RPCLimitPass == "") { 794 cfg.DisableRPC = true 795 } 796 797 if cfg.DisableRPC { 798 btcdLog.Infof("RPC service is disabled") 799 } 800 801 // Default RPC to listen on localhost only. 802 if !cfg.DisableRPC && len(cfg.RPCListeners) == 0 { 803 addrs, err := net.LookupHost("localhost") 804 if err != nil { 805 return nil, nil, err 806 } 807 cfg.RPCListeners = make([]string, 0, len(addrs)) 808 for _, addr := range addrs { 809 addr = net.JoinHostPort(addr, activeNetParams.rpcPort) 810 cfg.RPCListeners = append(cfg.RPCListeners, addr) 811 } 812 } 813 814 if cfg.RPCMaxConcurrentReqs < 0 { 815 str := "%s: The rpcmaxwebsocketconcurrentrequests option may " + 816 "not be less than 0 -- parsed [%d]" 817 err := fmt.Errorf(str, funcName, cfg.RPCMaxConcurrentReqs) 818 fmt.Fprintln(os.Stderr, err) 819 fmt.Fprintln(os.Stderr, usageMessage) 820 return nil, nil, err 821 } 822 823 // Validate the the minrelaytxfee. 824 cfg.minRelayTxFee, err = btcutil.NewAmount(cfg.MinRelayTxFee) 825 if err != nil { 826 str := "%s: invalid minrelaytxfee: %v" 827 err := fmt.Errorf(str, funcName, err) 828 fmt.Fprintln(os.Stderr, err) 829 fmt.Fprintln(os.Stderr, usageMessage) 830 return nil, nil, err 831 } 832 833 // Limit the max block size to a sane value. 834 if cfg.BlockMaxSize < blockMaxSizeMin || cfg.BlockMaxSize > 835 blockMaxSizeMax { 836 837 str := "%s: The blockmaxsize option must be in between %d " + 838 "and %d -- parsed [%d]" 839 err := fmt.Errorf(str, funcName, blockMaxSizeMin, 840 blockMaxSizeMax, cfg.BlockMaxSize) 841 fmt.Fprintln(os.Stderr, err) 842 fmt.Fprintln(os.Stderr, usageMessage) 843 return nil, nil, err 844 } 845 846 // Limit the max block weight to a sane value. 847 if cfg.BlockMaxWeight < blockMaxWeightMin || 848 cfg.BlockMaxWeight > blockMaxWeightMax { 849 850 str := "%s: The blockmaxweight option must be in between %d " + 851 "and %d -- parsed [%d]" 852 err := fmt.Errorf(str, funcName, blockMaxWeightMin, 853 blockMaxWeightMax, cfg.BlockMaxWeight) 854 fmt.Fprintln(os.Stderr, err) 855 fmt.Fprintln(os.Stderr, usageMessage) 856 return nil, nil, err 857 } 858 859 // Limit the max orphan count to a sane vlue. 860 if cfg.MaxOrphanTxs < 0 { 861 str := "%s: The maxorphantx option may not be less than 0 " + 862 "-- parsed [%d]" 863 err := fmt.Errorf(str, funcName, cfg.MaxOrphanTxs) 864 fmt.Fprintln(os.Stderr, err) 865 fmt.Fprintln(os.Stderr, usageMessage) 866 return nil, nil, err 867 } 868 869 // Limit the block priority and minimum block sizes to max block size. 870 cfg.BlockPrioritySize = minUint32(cfg.BlockPrioritySize, cfg.BlockMaxSize) 871 cfg.BlockMinSize = minUint32(cfg.BlockMinSize, cfg.BlockMaxSize) 872 cfg.BlockMinWeight = minUint32(cfg.BlockMinWeight, cfg.BlockMaxWeight) 873 874 switch { 875 // If the max block size isn't set, but the max weight is, then we'll 876 // set the limit for the max block size to a safe limit so weight takes 877 // precedence. 878 case cfg.BlockMaxSize == defaultBlockMaxSize && 879 cfg.BlockMaxWeight != defaultBlockMaxWeight: 880 881 cfg.BlockMaxSize = blockchain.MaxBlockBaseSize - 1000 882 883 // If the max block weight isn't set, but the block size is, then we'll 884 // scale the set weight accordingly based on the max block size value. 885 case cfg.BlockMaxSize != defaultBlockMaxSize && 886 cfg.BlockMaxWeight == defaultBlockMaxWeight: 887 888 cfg.BlockMaxWeight = cfg.BlockMaxSize * blockchain.WitnessScaleFactor 889 } 890 891 // Look for illegal characters in the user agent comments. 892 for _, uaComment := range cfg.UserAgentComments { 893 if strings.ContainsAny(uaComment, "/:()") { 894 err := fmt.Errorf("%s: The following characters must not "+ 895 "appear in user agent comments: '/', ':', '(', ')'", 896 funcName) 897 fmt.Fprintln(os.Stderr, err) 898 fmt.Fprintln(os.Stderr, usageMessage) 899 return nil, nil, err 900 } 901 } 902 903 // --txindex and --droptxindex do not mix. 904 if cfg.TxIndex && cfg.DropTxIndex { 905 err := fmt.Errorf("%s: the --txindex and --droptxindex "+ 906 "options may not be activated at the same time", 907 funcName) 908 fmt.Fprintln(os.Stderr, err) 909 fmt.Fprintln(os.Stderr, usageMessage) 910 return nil, nil, err 911 } 912 913 // --addrindex and --dropaddrindex do not mix. 914 if cfg.AddrIndex && cfg.DropAddrIndex { 915 err := fmt.Errorf("%s: the --addrindex and --dropaddrindex "+ 916 "options may not be activated at the same time", 917 funcName) 918 fmt.Fprintln(os.Stderr, err) 919 fmt.Fprintln(os.Stderr, usageMessage) 920 return nil, nil, err 921 } 922 923 // --addrindex and --droptxindex do not mix. 924 if cfg.AddrIndex && cfg.DropTxIndex { 925 err := fmt.Errorf("%s: the --addrindex and --droptxindex "+ 926 "options may not be activated at the same time "+ 927 "because the address index relies on the transaction "+ 928 "index", 929 funcName) 930 fmt.Fprintln(os.Stderr, err) 931 fmt.Fprintln(os.Stderr, usageMessage) 932 return nil, nil, err 933 } 934 935 // Check mining addresses are valid and saved parsed versions. 936 cfg.miningAddrs = make([]btcutil.Address, 0, len(cfg.MiningAddrs)) 937 for _, strAddr := range cfg.MiningAddrs { 938 addr, err := btcutil.DecodeAddress(strAddr, activeNetParams.Params) 939 if err != nil { 940 str := "%s: mining address '%s' failed to decode: %v" 941 err := fmt.Errorf(str, funcName, strAddr, err) 942 fmt.Fprintln(os.Stderr, err) 943 fmt.Fprintln(os.Stderr, usageMessage) 944 return nil, nil, err 945 } 946 if !addr.IsForNet(activeNetParams.Params) { 947 str := "%s: mining address '%s' is on the wrong network" 948 err := fmt.Errorf(str, funcName, strAddr) 949 fmt.Fprintln(os.Stderr, err) 950 fmt.Fprintln(os.Stderr, usageMessage) 951 return nil, nil, err 952 } 953 cfg.miningAddrs = append(cfg.miningAddrs, addr) 954 } 955 956 // Ensure there is at least one mining address when the generate flag is 957 // set. 958 if cfg.Generate && len(cfg.MiningAddrs) == 0 { 959 str := "%s: the generate flag is set, but there are no mining " + 960 "addresses specified " 961 err := fmt.Errorf(str, funcName) 962 fmt.Fprintln(os.Stderr, err) 963 fmt.Fprintln(os.Stderr, usageMessage) 964 return nil, nil, err 965 } 966 967 // Add default port to all listener addresses if needed and remove 968 // duplicate addresses. 969 cfg.Listeners = normalizeAddresses(cfg.Listeners, 970 activeNetParams.DefaultPort) 971 972 // Add default port to all rpc listener addresses if needed and remove 973 // duplicate addresses. 974 cfg.RPCListeners = normalizeAddresses(cfg.RPCListeners, 975 activeNetParams.rpcPort) 976 977 // Only allow TLS to be disabled if the RPC is bound to localhost 978 // addresses. 979 if !cfg.DisableRPC && cfg.DisableTLS { 980 for _, addr := range cfg.RPCListeners { 981 _, _, err := net.SplitHostPort(addr) 982 if err != nil { 983 str := "%s: RPC listen interface '%s' is " + 984 "invalid: %v" 985 err := fmt.Errorf(str, funcName, addr, err) 986 fmt.Fprintln(os.Stderr, err) 987 fmt.Fprintln(os.Stderr, usageMessage) 988 return nil, nil, err 989 } 990 } 991 } 992 993 // Add default port to all added peer addresses if needed and remove 994 // duplicate addresses. 995 cfg.AddPeers = normalizeAddresses(cfg.AddPeers, 996 activeNetParams.DefaultPort) 997 cfg.ConnectPeers = normalizeAddresses(cfg.ConnectPeers, 998 activeNetParams.DefaultPort) 999 1000 // --noonion and --onion do not mix. 1001 if cfg.NoOnion && cfg.OnionProxy != "" { 1002 err := fmt.Errorf("%s: the --noonion and --onion options may "+ 1003 "not be activated at the same time", funcName) 1004 fmt.Fprintln(os.Stderr, err) 1005 fmt.Fprintln(os.Stderr, usageMessage) 1006 return nil, nil, err 1007 } 1008 1009 // Check the checkpoints for syntax errors. 1010 cfg.addCheckpoints, err = parseCheckpoints(cfg.AddCheckpoints) 1011 if err != nil { 1012 str := "%s: Error parsing checkpoints: %v" 1013 err := fmt.Errorf(str, funcName, err) 1014 fmt.Fprintln(os.Stderr, err) 1015 fmt.Fprintln(os.Stderr, usageMessage) 1016 return nil, nil, err 1017 } 1018 1019 // Tor stream isolation requires either proxy or onion proxy to be set. 1020 if cfg.TorIsolation && cfg.Proxy == "" && cfg.OnionProxy == "" { 1021 str := "%s: Tor stream isolation requires either proxy or " + 1022 "onionproxy to be set" 1023 err := fmt.Errorf(str, funcName) 1024 fmt.Fprintln(os.Stderr, err) 1025 fmt.Fprintln(os.Stderr, usageMessage) 1026 return nil, nil, err 1027 } 1028 1029 // Setup dial and DNS resolution (lookup) functions depending on the 1030 // specified options. The default is to use the standard 1031 // net.DialTimeout function as well as the system DNS resolver. When a 1032 // proxy is specified, the dial function is set to the proxy specific 1033 // dial function and the lookup is set to use tor (unless --noonion is 1034 // specified in which case the system DNS resolver is used). 1035 cfg.dial = net.DialTimeout 1036 cfg.lookup = net.LookupIP 1037 if cfg.Proxy != "" { 1038 _, _, err := net.SplitHostPort(cfg.Proxy) 1039 if err != nil { 1040 str := "%s: Proxy address '%s' is invalid: %v" 1041 err := fmt.Errorf(str, funcName, cfg.Proxy, err) 1042 fmt.Fprintln(os.Stderr, err) 1043 fmt.Fprintln(os.Stderr, usageMessage) 1044 return nil, nil, err 1045 } 1046 1047 // Tor isolation flag means proxy credentials will be overridden 1048 // unless there is also an onion proxy configured in which case 1049 // that one will be overridden. 1050 torIsolation := false 1051 if cfg.TorIsolation && cfg.OnionProxy == "" && 1052 (cfg.ProxyUser != "" || cfg.ProxyPass != "") { 1053 1054 torIsolation = true 1055 fmt.Fprintln(os.Stderr, "Tor isolation set -- "+ 1056 "overriding specified proxy user credentials") 1057 } 1058 1059 proxy := &socks.Proxy{ 1060 Addr: cfg.Proxy, 1061 Username: cfg.ProxyUser, 1062 Password: cfg.ProxyPass, 1063 TorIsolation: torIsolation, 1064 } 1065 cfg.dial = proxy.DialTimeout 1066 1067 // Treat the proxy as tor and perform DNS resolution through it 1068 // unless the --noonion flag is set or there is an 1069 // onion-specific proxy configured. 1070 if !cfg.NoOnion && cfg.OnionProxy == "" { 1071 cfg.lookup = func(host string) ([]net.IP, error) { 1072 return connmgr.TorLookupIP(host, cfg.Proxy) 1073 } 1074 } 1075 } 1076 1077 // Setup onion address dial function depending on the specified options. 1078 // The default is to use the same dial function selected above. However, 1079 // when an onion-specific proxy is specified, the onion address dial 1080 // function is set to use the onion-specific proxy while leaving the 1081 // normal dial function as selected above. This allows .onion address 1082 // traffic to be routed through a different proxy than normal traffic. 1083 if cfg.OnionProxy != "" { 1084 _, _, err := net.SplitHostPort(cfg.OnionProxy) 1085 if err != nil { 1086 str := "%s: Onion proxy address '%s' is invalid: %v" 1087 err := fmt.Errorf(str, funcName, cfg.OnionProxy, err) 1088 fmt.Fprintln(os.Stderr, err) 1089 fmt.Fprintln(os.Stderr, usageMessage) 1090 return nil, nil, err 1091 } 1092 1093 // Tor isolation flag means onion proxy credentials will be 1094 // overridden. 1095 if cfg.TorIsolation && 1096 (cfg.OnionProxyUser != "" || cfg.OnionProxyPass != "") { 1097 fmt.Fprintln(os.Stderr, "Tor isolation set -- "+ 1098 "overriding specified onionproxy user "+ 1099 "credentials ") 1100 } 1101 1102 cfg.oniondial = func(network, addr string, timeout time.Duration) (net.Conn, error) { 1103 proxy := &socks.Proxy{ 1104 Addr: cfg.OnionProxy, 1105 Username: cfg.OnionProxyUser, 1106 Password: cfg.OnionProxyPass, 1107 TorIsolation: cfg.TorIsolation, 1108 } 1109 return proxy.DialTimeout(network, addr, timeout) 1110 } 1111 1112 // When configured in bridge mode (both --onion and --proxy are 1113 // configured), it means that the proxy configured by --proxy is 1114 // not a tor proxy, so override the DNS resolution to use the 1115 // onion-specific proxy. 1116 if cfg.Proxy != "" { 1117 cfg.lookup = func(host string) ([]net.IP, error) { 1118 return connmgr.TorLookupIP(host, cfg.OnionProxy) 1119 } 1120 } 1121 } else { 1122 cfg.oniondial = cfg.dial 1123 } 1124 1125 // Specifying --noonion means the onion address dial function results in 1126 // an error. 1127 if cfg.NoOnion { 1128 cfg.oniondial = func(a, b string, t time.Duration) (net.Conn, error) { 1129 return nil, errors.New("tor has been disabled") 1130 } 1131 } 1132 1133 // Warn about missing config file only after all other configuration is 1134 // done. This prevents the warning on help messages and invalid 1135 // options. Note this should go directly before the return. 1136 if configFileError != nil { 1137 btcdLog.Warnf("%v", configFileError) 1138 } 1139 1140 return &cfg, remainingArgs, nil 1141 } 1142 1143 // createDefaultConfig copies the file sample-lbcd.conf to the given destination path, 1144 // and populates it with some randomly generated RPC username and password. 1145 func createDefaultConfigFile(destinationPath string) error { 1146 // Create the destination directory if it does not exists 1147 err := os.MkdirAll(filepath.Dir(destinationPath), 0700) 1148 if err != nil { 1149 return err 1150 } 1151 1152 // We assume sample config file path is same as binary 1153 path, err := filepath.Abs(filepath.Dir(os.Args[0])) 1154 if err != nil { 1155 return err 1156 } 1157 sampleConfigPath := filepath.Join(path, sampleConfigFilename) 1158 1159 // We generate a random user and password 1160 randomBytes := make([]byte, 20) 1161 _, err = rand.Read(randomBytes) 1162 if err != nil { 1163 return err 1164 } 1165 generatedRPCUser := base64.StdEncoding.EncodeToString(randomBytes) 1166 1167 _, err = rand.Read(randomBytes) 1168 if err != nil { 1169 return err 1170 } 1171 generatedRPCPass := base64.StdEncoding.EncodeToString(randomBytes) 1172 1173 var reader *bufio.Reader 1174 src, err := os.Open(sampleConfigPath) 1175 if err != nil { 1176 // Fall back to sample config embedded at build time. 1177 reader = bufio.NewReader(strings.NewReader(sampleConfig)) 1178 } else { 1179 reader = bufio.NewReader(src) 1180 defer src.Close() 1181 } 1182 1183 dest, err := os.OpenFile(destinationPath, 1184 os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) 1185 if err != nil { 1186 return err 1187 } 1188 defer dest.Close() 1189 1190 // We copy every line from the sample config file to the destination, 1191 // only replacing the two lines for rpcuser and rpcpass 1192 for err != io.EOF { 1193 var line string 1194 line, err = reader.ReadString('\n') 1195 if err != nil && err != io.EOF { 1196 return err 1197 } 1198 1199 if strings.Contains(line, "rpcuser=") { 1200 line = "rpcuser=" + generatedRPCUser + "\n" 1201 } else if strings.Contains(line, "rpcpass=") { 1202 line = "rpcpass=" + generatedRPCPass + "\n" 1203 } 1204 1205 if _, err := dest.WriteString(line); err != nil { 1206 return err 1207 } 1208 } 1209 1210 return nil 1211 } 1212 1213 // btcdDial connects to the address on the named network using the appropriate 1214 // dial function depending on the address and configuration options. For 1215 // example, .onion addresses will be dialed using the onion specific proxy if 1216 // one was specified, but will otherwise use the normal dial function (which 1217 // could itself use a proxy or not). 1218 func btcdDial(addr net.Addr) (net.Conn, error) { 1219 if strings.Contains(addr.String(), ".onion:") { 1220 return cfg.oniondial(addr.Network(), addr.String(), 1221 defaultConnectTimeout) 1222 } 1223 return cfg.dial(addr.Network(), addr.String(), defaultConnectTimeout) 1224 } 1225 1226 // btcdLookup resolves the IP of the given host using the correct DNS lookup 1227 // function depending on the configuration options. For example, addresses will 1228 // be resolved using tor when the --proxy flag was specified unless --noonion 1229 // was also specified in which case the normal system DNS resolver will be used. 1230 // 1231 // Any attempt to resolve a tor address (.onion) will return an error since they 1232 // are not intended to be resolved outside of the tor proxy. 1233 func btcdLookup(host string) ([]net.IP, error) { 1234 if strings.HasSuffix(host, ".onion") { 1235 return nil, fmt.Errorf("attempt to resolve tor address %s", host) 1236 } 1237 1238 return cfg.lookup(host) 1239 }