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