Copy btcd RPC listening behavior.
This change copies the listening behavior of btcd by replacing the --serverport option with --listen. By default, btcwallet will only listen for localhost connections, but with this change it will be possible to add listeners for remote connections. This was added due to finding a bug with updateConfigWithActiveParams. After consulting the btcd source code, the bug was fixed by replacing the function (as it was no longer needed) when the new listening code was introduced. While here, mask out the password flag from being shown in the help message.
This commit is contained in:
parent
52525dd302
commit
8669129917
5 changed files with 127 additions and 62 deletions
|
@ -186,14 +186,6 @@ func (store *AccountStore) CreateEncryptedWallet(name, desc string, passphrase [
|
|||
return ErrAcctExists
|
||||
}
|
||||
|
||||
// Decide which Bitcoin network must be used.
|
||||
var net btcwire.BitcoinNet
|
||||
if cfg.MainNet {
|
||||
net = btcwire.MainNet
|
||||
} else {
|
||||
net = btcwire.TestNet3
|
||||
}
|
||||
|
||||
// Get current block's height and hash.
|
||||
bs, err := GetCurBlock()
|
||||
if err != nil {
|
||||
|
@ -201,7 +193,7 @@ func (store *AccountStore) CreateEncryptedWallet(name, desc string, passphrase [
|
|||
}
|
||||
|
||||
// Create new wallet in memory.
|
||||
wlt, err := wallet.NewWallet(name, desc, passphrase, net, &bs)
|
||||
wlt, err := wallet.NewWallet(name, desc, passphrase, cfg.Net(), &bs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
2
cmd.go
2
cmd.go
|
@ -225,7 +225,7 @@ func main() {
|
|||
go DirtyAccountSyncer()
|
||||
|
||||
go func() {
|
||||
s, err := newServer()
|
||||
s, err := newServer(cfg.SvrListeners)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to create HTTP server: %v", err)
|
||||
os.Exit(1)
|
||||
|
|
91
config.go
91
config.go
|
@ -44,22 +44,22 @@ var (
|
|||
)
|
||||
|
||||
type config struct {
|
||||
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
|
||||
CAFile string `long:"cafile" description:"File containing root certificates to authenticate a TLS connections with btcd"`
|
||||
Connect string `short:"c" long:"connect" description:"Server and port of btcd instance to connect to"`
|
||||
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"`
|
||||
ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"`
|
||||
SvrPort string `short:"p" long:"serverport" description:"Port to serve frontend websocket connections on (default: 18332, mainnet: 8332)"`
|
||||
DataDir string `short:"D" long:"datadir" description:"Directory to store wallets and transactions"`
|
||||
Username string `short:"u" long:"username" description:"Username for btcd authorization"`
|
||||
Password string `short:"P" long:"password" description:"Password for btcd authorization"`
|
||||
RPCCert string `long:"rpccert" description:"File containing the certificate file"`
|
||||
RPCKey string `long:"rpckey" description:"File containing the certificate key"`
|
||||
MainNet bool `long:"mainnet" description:"*DISABLED* Use the main Bitcoin network (default testnet3)"`
|
||||
Proxy string `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
|
||||
ProxyUser string `long:"proxyuser" description:"Username for proxy server"`
|
||||
ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"`
|
||||
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
||||
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
|
||||
CAFile string `long:"cafile" description:"File containing root certificates to authenticate a TLS connections with btcd"`
|
||||
Connect string `short:"c" long:"connect" description:"Server and port of btcd instance to connect to"`
|
||||
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"`
|
||||
ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"`
|
||||
SvrListeners []string `long:"listen" description:"Listen for RPC/websocket connections on this interface/port (default no listening. default port: 18332, mainnet: 8332)"`
|
||||
DataDir string `short:"D" long:"datadir" description:"Directory to store wallets and transactions"`
|
||||
Username string `short:"u" long:"username" description:"Username for btcd authorization"`
|
||||
Password string `short:"P" long:"password" default-mask:"-" description:"Password for btcd authorization"`
|
||||
RPCCert string `long:"rpccert" description:"File containing the certificate file"`
|
||||
RPCKey string `long:"rpckey" description:"File containing the certificate key"`
|
||||
MainNet bool `long:"mainnet" description:"*DISABLED* Use the main Bitcoin network (default testnet3)"`
|
||||
Proxy string `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
|
||||
ProxyUser string `long:"proxyuser" description:"Username for proxy server"`
|
||||
ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"`
|
||||
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
||||
}
|
||||
|
||||
// cleanAndExpandPath expands environement variables and leading ~ in the
|
||||
|
@ -76,18 +76,28 @@ func cleanAndExpandPath(path string) string {
|
|||
return filepath.Clean(os.ExpandEnv(path))
|
||||
}
|
||||
|
||||
// updateConfigWithActiveParams update the passed config with parameters
|
||||
// from the active net params if the relevant options in the passed config
|
||||
// object are the default so options specified by the user on the command line
|
||||
// are not overridden.
|
||||
func updateConfigWithActiveParams(cfg *config) {
|
||||
if cfg.Connect == netParams(defaultBtcNet).connect {
|
||||
cfg.Connect = activeNetParams.connect
|
||||
// removeDuplicateAddresses returns a new slice with all duplicate entries in
|
||||
// addrs removed.
|
||||
func removeDuplicateAddresses(addrs []string) []string {
|
||||
result := make([]string, 0)
|
||||
seen := map[string]bool{}
|
||||
for _, val := range addrs {
|
||||
if _, ok := seen[val]; !ok {
|
||||
result = append(result, val)
|
||||
seen[val] = true
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// normalizeAddresses returns a new slice with all the passed peer addresses
|
||||
// normalized with the given default port, and all duplicates removed.
|
||||
func normalizeAddresses(addrs []string, defaultPort string) []string {
|
||||
for i, addr := range addrs {
|
||||
addrs[i] = normalizeAddress(addr, defaultPort)
|
||||
}
|
||||
|
||||
if cfg.SvrPort == netParams(defaultBtcNet).svrPort {
|
||||
cfg.SvrPort = activeNetParams.svrPort
|
||||
}
|
||||
return removeDuplicateAddresses(addrs)
|
||||
}
|
||||
|
||||
// filesExists reports whether the named file or directory exists.
|
||||
|
@ -129,7 +139,6 @@ func loadConfig() (*config, []string, error) {
|
|||
CAFile: defaultCAFile,
|
||||
ConfigFile: defaultConfigFile,
|
||||
Connect: netParams(defaultBtcNet).connect,
|
||||
SvrPort: netParams(defaultBtcNet).svrPort,
|
||||
DataDir: defaultDataDir,
|
||||
RPCKey: defaultRPCKeyFile,
|
||||
RPCCert: defaultRPCCertFile,
|
||||
|
@ -189,14 +198,10 @@ func loadConfig() (*config, []string, error) {
|
|||
log.Warnf("%v", configFileError)
|
||||
}
|
||||
|
||||
// TODO(jrick): Enable mainnet support again when ready.
|
||||
cfg.MainNet = false
|
||||
|
||||
// Choose the active network params based on the mainnet net flag.
|
||||
if cfg.MainNet {
|
||||
activeNetParams = netParams(btcwire.MainNet)
|
||||
//activeNetParams = netParams(btcwire.MainNet)
|
||||
}
|
||||
updateConfigWithActiveParams(&cfg)
|
||||
|
||||
// Validate debug log level
|
||||
if !validLogLevel(cfg.DebugLevel) {
|
||||
|
@ -210,6 +215,28 @@ func loadConfig() (*config, []string, error) {
|
|||
// Add default port to connect flag if missing.
|
||||
cfg.Connect = normalizeAddress(cfg.Connect, activeNetParams.btcdPort)
|
||||
|
||||
if len(cfg.SvrListeners) == 0 {
|
||||
addrs, err := net.LookupHost("localhost")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cfg.SvrListeners = make([]string, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
addr = net.JoinHostPort(addr, activeNetParams.svrPort)
|
||||
cfg.SvrListeners = append(cfg.SvrListeners, addr)
|
||||
}
|
||||
}
|
||||
|
||||
// Add default port to all listener addresses if needed and remove
|
||||
// duplicate addresses.
|
||||
cfg.SvrListeners = normalizeAddresses(cfg.SvrListeners,
|
||||
activeNetParams.svrPort)
|
||||
|
||||
// Add default port to all rpc listener addresses if needed and remove
|
||||
// duplicate addresses.
|
||||
cfg.SvrListeners = normalizeAddresses(cfg.SvrListeners,
|
||||
activeNetParams.svrPort)
|
||||
|
||||
// Expand environment variable and leading ~ for filepaths.
|
||||
cfg.CAFile = cleanAndExpandPath(cfg.CAFile)
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@
|
|||
; username=
|
||||
; password=
|
||||
|
||||
; Port to serve websocket connections for wallet frontends.
|
||||
; serverport=18332
|
||||
; Listen for RPC/websocket connections on the following ports/interfaces:
|
||||
; listen=localhost:18332
|
||||
|
|
82
sockets.go
82
sockets.go
|
@ -41,6 +41,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
@ -101,19 +102,57 @@ var (
|
|||
// server holds the items the RPC server may need to access (auth,
|
||||
// config, shutdown, etc.)
|
||||
type server struct {
|
||||
port string
|
||||
wg sync.WaitGroup
|
||||
listeners []net.Listener
|
||||
authsha [sha256.Size]byte
|
||||
}
|
||||
|
||||
// parseListeners splits the list of listen addresses passed in addrs into
|
||||
// IPv4 and IPv6 slices and returns them. This allows easy creation of the
|
||||
// listeners on the correct interface "tcp4" and "tcp6". It also properly
|
||||
// detects addresses which apply to "all interfaces" and adds the address to
|
||||
// both slices.
|
||||
func parseListeners(addrs []string) ([]string, []string, error) {
|
||||
ipv4ListenAddrs := make([]string, 0, len(addrs)*2)
|
||||
ipv6ListenAddrs := make([]string, 0, len(addrs)*2)
|
||||
for _, addr := range addrs {
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
// Shouldn't happen due to already being normalized.
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Empty host or host of * on plan9 is both IPv4 and IPv6.
|
||||
if host == "" || (host == "*" && runtime.GOOS == "plan9") {
|
||||
ipv4ListenAddrs = append(ipv4ListenAddrs, addr)
|
||||
ipv6ListenAddrs = append(ipv6ListenAddrs, addr)
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse the IP.
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
return nil, nil, fmt.Errorf("'%s' is not a valid IP "+
|
||||
"address", host)
|
||||
}
|
||||
|
||||
// To4 returns nil when the IP is not an IPv4 address, so use
|
||||
// this determine the address type.
|
||||
if ip.To4() == nil {
|
||||
ipv6ListenAddrs = append(ipv6ListenAddrs, addr)
|
||||
} else {
|
||||
ipv4ListenAddrs = append(ipv4ListenAddrs, addr)
|
||||
}
|
||||
}
|
||||
return ipv4ListenAddrs, ipv6ListenAddrs, nil
|
||||
}
|
||||
|
||||
// newServer returns a new instance of the server struct.
|
||||
func newServer() (*server, error) {
|
||||
func newServer(listenAddrs []string) (*server, error) {
|
||||
login := cfg.Username + ":" + cfg.Password
|
||||
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login))
|
||||
s := server{
|
||||
authsha: sha256.Sum256([]byte(auth)),
|
||||
port: cfg.SvrPort,
|
||||
}
|
||||
|
||||
// Check for existence of cert file and key file
|
||||
|
@ -133,24 +172,31 @@ func newServer() (*server, error) {
|
|||
Certificates: []tls.Certificate{keypair},
|
||||
}
|
||||
|
||||
// IPv4 listener.
|
||||
var listeners []net.Listener
|
||||
listenAddr4 := net.JoinHostPort("127.0.0.1", s.port)
|
||||
listener4, err := tls.Listen("tcp4", listenAddr4, &tlsConfig)
|
||||
if err != nil {
|
||||
log.Errorf("RPCS: Couldn't create listener: %v", err)
|
||||
return nil, err
|
||||
ipv4ListenAddrs, ipv6ListenAddrs, err := parseListeners(listenAddrs)
|
||||
listeners := make([]net.Listener, 0,
|
||||
len(ipv6ListenAddrs)+len(ipv4ListenAddrs))
|
||||
for _, addr := range ipv4ListenAddrs {
|
||||
listener, err := tls.Listen("tcp4", addr, &tlsConfig)
|
||||
if err != nil {
|
||||
log.Warnf("RPCS: Can't listen on %s: %v", addr,
|
||||
err)
|
||||
continue
|
||||
}
|
||||
listeners = append(listeners, listener)
|
||||
}
|
||||
listeners = append(listeners, listener4)
|
||||
|
||||
// IPv6 listener.
|
||||
listenAddr6 := net.JoinHostPort("::1", s.port)
|
||||
listener6, err := tls.Listen("tcp6", listenAddr6, &tlsConfig)
|
||||
if err != nil {
|
||||
log.Errorf("RPCS: Couldn't create listener: %v", err)
|
||||
return nil, err
|
||||
for _, addr := range ipv6ListenAddrs {
|
||||
listener, err := tls.Listen("tcp6", addr, &tlsConfig)
|
||||
if err != nil {
|
||||
log.Warnf("RPCS: Can't listen on %s: %v", addr,
|
||||
err)
|
||||
continue
|
||||
}
|
||||
listeners = append(listeners, listener)
|
||||
}
|
||||
if len(listeners) == 0 {
|
||||
return nil, errors.New("RPCS: No valid listen address")
|
||||
}
|
||||
listeners = append(listeners, listener6)
|
||||
|
||||
s.listeners = listeners
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue