aboutsummaryrefslogtreecommitdiffstats
path: root/node
diff options
context:
space:
mode:
authorMartin Holst Swende <martin@swende.se>2018-02-12 20:52:07 +0800
committerPéter Szilágyi <peterke@gmail.com>2018-02-12 20:52:07 +0800
commit589b603a9b1e17930d1e83ca64ce7cdc4c3d5c85 (patch)
treec1993266024190bd6789a471f5957b9dfa6f4dbc /node
parent9123eceb0f78f69e88d909a56ad7fadb75570198 (diff)
downloaddexon-589b603a9b1e17930d1e83ca64ce7cdc4c3d5c85.tar.gz
dexon-589b603a9b1e17930d1e83ca64ce7cdc4c3d5c85.tar.zst
dexon-589b603a9b1e17930d1e83ca64ce7cdc4c3d5c85.zip
rpc: dns rebind protection (#15962)
* cmd,node,rpc: add allowedHosts to prevent dns rebinding attacks * p2p,node: Fix bug with dumpconfig introduced in r54aeb8e4c0bb9f0e7a6c67258af67df3b266af3d * rpc: add wildcard support for rpcallowedhosts + go fmt * cmd/geth, cmd/utils, node, rpc: ignore direct ip(v4/6) addresses in rpc virtual hostnames check * http, rpc, utils: make vhosts into map, address review concerns * node: change log messages to use geth standard (not sprintf) * rpc: fix spelling
Diffstat (limited to 'node')
-rw-r--r--node/api.go12
-rw-r--r--node/config.go11
-rw-r--r--node/node.go29
3 files changed, 34 insertions, 18 deletions
diff --git a/node/api.go b/node/api.go
index 1b04b7093..4e9b1edc4 100644
--- a/node/api.go
+++ b/node/api.go
@@ -114,7 +114,7 @@ func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription,
}
// StartRPC starts the HTTP RPC API server.
-func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string) (bool, error) {
+func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
@@ -141,6 +141,14 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
}
+ allowedVHosts := api.node.config.HTTPVirtualHosts
+ if vhosts != nil {
+ allowedVHosts = nil
+ for _, vhost := range strings.Split(*host, ",") {
+ allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost))
+ }
+ }
+
modules := api.node.httpWhitelist
if apis != nil {
modules = nil
@@ -149,7 +157,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
}
- if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins); err != nil {
+ if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts); err != nil {
return false, err
}
return true, nil
diff --git a/node/config.go b/node/config.go
index 7a0c1688e..dda24583e 100644
--- a/node/config.go
+++ b/node/config.go
@@ -105,6 +105,15 @@ type Config struct {
// useless for custom HTTP clients.
HTTPCors []string `toml:",omitempty"`
+ // HTTPVirtualHosts is the list of virtual hostnames which are allowed on incoming requests.
+ // This is by default {'localhost'}. Using this prevents attacks like
+ // DNS rebinding, which bypasses SOP by simply masquerading as being within the same
+ // origin. These attacks do not utilize CORS, since they are not cross-domain.
+ // By explicitly checking the Host-header, the server will not allow requests
+ // made against the server with a malicious host domain.
+ // Requests using ip address directly are not affected
+ HTTPVirtualHosts []string `toml:",omitempty"`
+
// HTTPModules is a list of API modules to expose via the HTTP RPC interface.
// If the module list is empty, all RPC API endpoints designated public will be
// exposed.
@@ -137,7 +146,7 @@ type Config struct {
WSExposeAll bool `toml:",omitempty"`
// Logger is a custom logger to use with the p2p.Server.
- Logger log.Logger
+ Logger log.Logger `toml:",omitempty"`
}
// IPCEndpoint resolves an IPC endpoint based on a configured value, taking into
diff --git a/node/node.go b/node/node.go
index ff7258033..37bd2eb3c 100644
--- a/node/node.go
+++ b/node/node.go
@@ -263,7 +263,7 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error {
n.stopInProc()
return err
}
- if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors); err != nil {
+ if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts); err != nil {
n.stopIPC()
n.stopInProc()
return err
@@ -287,7 +287,7 @@ func (n *Node) startInProc(apis []rpc.API) error {
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- n.log.Debug(fmt.Sprintf("InProc registered %T under '%s'", api.Service, api.Namespace))
+ n.log.Debug("InProc registered", "service", api.Service, "namespace", api.Namespace)
}
n.inprocHandler = handler
return nil
@@ -313,7 +313,7 @@ func (n *Node) startIPC(apis []rpc.API) error {
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- n.log.Debug(fmt.Sprintf("IPC registered %T under '%s'", api.Service, api.Namespace))
+ n.log.Debug("IPC registered", "service", api.Service, "namespace", api.Namespace)
}
// All APIs registered, start the IPC listener
var (
@@ -324,7 +324,7 @@ func (n *Node) startIPC(apis []rpc.API) error {
return err
}
go func() {
- n.log.Info(fmt.Sprintf("IPC endpoint opened: %s", n.ipcEndpoint))
+ n.log.Info("IPC endpoint opened", "url", fmt.Sprintf("%s", n.ipcEndpoint))
for {
conn, err := listener.Accept()
@@ -337,7 +337,7 @@ func (n *Node) startIPC(apis []rpc.API) error {
return
}
// Not closed, just some error; report and continue
- n.log.Error(fmt.Sprintf("IPC accept failed: %v", err))
+ n.log.Error("IPC accept failed", "err", err)
continue
}
go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions)
@@ -356,7 +356,7 @@ func (n *Node) stopIPC() {
n.ipcListener.Close()
n.ipcListener = nil
- n.log.Info(fmt.Sprintf("IPC endpoint closed: %s", n.ipcEndpoint))
+ n.log.Info("IPC endpoint closed", "endpoint", n.ipcEndpoint)
}
if n.ipcHandler != nil {
n.ipcHandler.Stop()
@@ -365,7 +365,7 @@ func (n *Node) stopIPC() {
}
// startHTTP initializes and starts the HTTP RPC endpoint.
-func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string) error {
+func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string) error {
// Short circuit if the HTTP endpoint isn't being exposed
if endpoint == "" {
return nil
@@ -382,7 +382,7 @@ func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- n.log.Debug(fmt.Sprintf("HTTP registered %T under '%s'", api.Service, api.Namespace))
+ n.log.Debug("HTTP registered", "service", api.Service, "namespace", api.Namespace)
}
}
// All APIs registered, start the HTTP listener
@@ -393,9 +393,8 @@ func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors
if listener, err = net.Listen("tcp", endpoint); err != nil {
return err
}
- go rpc.NewHTTPServer(cors, handler).Serve(listener)
- n.log.Info(fmt.Sprintf("HTTP endpoint opened: http://%s", endpoint))
-
+ go rpc.NewHTTPServer(cors, vhosts, handler).Serve(listener)
+ n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "hvosts", strings.Join(vhosts, ","))
// All listeners booted successfully
n.httpEndpoint = endpoint
n.httpListener = listener
@@ -410,7 +409,7 @@ func (n *Node) stopHTTP() {
n.httpListener.Close()
n.httpListener = nil
- n.log.Info(fmt.Sprintf("HTTP endpoint closed: http://%s", n.httpEndpoint))
+ n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint))
}
if n.httpHandler != nil {
n.httpHandler.Stop()
@@ -436,7 +435,7 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- n.log.Debug(fmt.Sprintf("WebSocket registered %T under '%s'", api.Service, api.Namespace))
+ n.log.Debug("WebSocket registered", "service", api.Service, "namespace", api.Namespace)
}
}
// All APIs registered, start the HTTP listener
@@ -448,7 +447,7 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig
return err
}
go rpc.NewWSServer(wsOrigins, handler).Serve(listener)
- n.log.Info(fmt.Sprintf("WebSocket endpoint opened: ws://%s", listener.Addr()))
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
// All listeners booted successfully
n.wsEndpoint = endpoint
@@ -464,7 +463,7 @@ func (n *Node) stopWS() {
n.wsListener.Close()
n.wsListener = nil
- n.log.Info(fmt.Sprintf("WebSocket endpoint closed: ws://%s", n.wsEndpoint))
+ n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint))
}
if n.wsHandler != nil {
n.wsHandler.Stop()