open-vault/helper/proxyutil/proxyutil.go
Jeff Mitchell e52b554c0b
Add an idle timeout for the server (#4760)
* Add an idle timeout for the server

Because tidy operations can be long-running, this also changes all tidy
operations to behave the same operationally (kick off the process, get a
warning back, log errors to server log) and makes them all run in a
goroutine.

This could mean a sort of hard stop if Vault gets sealed because the
function won't have the read lock. This should generally be okay
(running tidy again should pick back up where it left off), but future
work could use cleanup funcs to trigger the functions to stop.

* Fix up tidy test

* Add deadline to cluster connections and an idle timeout to the cluster server, plus add readheader/read timeout to api server
2018-06-16 18:21:33 -04:00

81 lines
2 KiB
Go

package proxyutil
import (
"fmt"
"net"
"sync"
"time"
proxyproto "github.com/armon/go-proxyproto"
"github.com/hashicorp/errwrap"
sockaddr "github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/vault/helper/parseutil"
)
// ProxyProtoConfig contains configuration for the PROXY protocol
type ProxyProtoConfig struct {
sync.RWMutex
Behavior string
AuthorizedAddrs []*sockaddr.SockAddrMarshaler `json:"authorized_addrs"`
}
func (p *ProxyProtoConfig) SetAuthorizedAddrs(addrs interface{}) error {
aa, err := parseutil.ParseAddrs(addrs)
if err != nil {
return err
}
p.AuthorizedAddrs = aa
return nil
}
// WrapInProxyProto wraps the given listener in the PROXY protocol. If behavior
// is "use_if_authorized" or "deny_if_unauthorized" it also configures a
// SourceCheck based on the given ProxyProtoConfig. In an error case it returns
// the original listener and the error.
func WrapInProxyProto(listener net.Listener, config *ProxyProtoConfig) (net.Listener, error) {
config.Lock()
defer config.Unlock()
var newLn *proxyproto.Listener
switch config.Behavior {
case "use_always":
newLn = &proxyproto.Listener{
Listener: listener,
ProxyHeaderTimeout: 10 * time.Second,
}
case "allow_authorized", "deny_unauthorized":
newLn = &proxyproto.Listener{
Listener: listener,
ProxyHeaderTimeout: 10 * time.Second,
SourceCheck: func(addr net.Addr) (bool, error) {
config.RLock()
defer config.RUnlock()
sa, err := sockaddr.NewSockAddr(addr.String())
if err != nil {
return false, errwrap.Wrapf("error parsing remote address: {{err}}", err)
}
for _, authorizedAddr := range config.AuthorizedAddrs {
if authorizedAddr.Contains(sa) {
return true, nil
}
}
if config.Behavior == "allow_authorized" {
return false, nil
}
return false, proxyproto.ErrInvalidUpstream
},
}
default:
return listener, fmt.Errorf("unknown behavior type for proxy proto config")
}
return newLn, nil
}