open-vault/helper/proxyutil/proxyutil.go

84 lines
2.1 KiB
Go
Raw Normal View History

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2017-08-02 22:24:12 +00:00
package proxyutil
import (
"errors"
2017-08-02 22:24:12 +00:00
"fmt"
"net"
"sync"
"time"
2017-08-02 22:24:12 +00:00
"github.com/hashicorp/go-secure-stdlib/parseutil"
2017-08-02 22:24:12 +00:00
sockaddr "github.com/hashicorp/go-sockaddr"
proxyproto "github.com/pires/go-proxyproto"
2017-08-02 22:24:12 +00:00
)
// 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 {
2018-04-17 22:52:09 +00:00
aa, err := parseutil.ParseAddrs(addrs)
if err != nil {
return err
2017-08-02 22:24:12 +00:00
}
2018-04-17 22:52:09 +00:00
p.AuthorizedAddrs = aa
2017-08-02 22:24:12 +00:00
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,
ReadHeaderTimeout: 10 * time.Second,
2017-08-02 22:24:12 +00:00
}
case "allow_authorized", "deny_unauthorized":
newLn = &proxyproto.Listener{
Listener: listener,
ReadHeaderTimeout: 10 * time.Second,
Policy: func(addr net.Addr) (proxyproto.Policy, error) {
2017-08-02 22:24:12 +00:00
config.RLock()
defer config.RUnlock()
sa, err := sockaddr.NewSockAddr(addr.String())
if err != nil {
return proxyproto.REJECT, fmt.Errorf("error parsing remote address: %w", err)
2017-08-02 22:24:12 +00:00
}
for _, authorizedAddr := range config.AuthorizedAddrs {
if authorizedAddr.Contains(sa) {
return proxyproto.USE, nil
2017-08-02 22:24:12 +00:00
}
}
if config.Behavior == "allow_authorized" {
return proxyproto.IGNORE, nil
2017-08-02 22:24:12 +00:00
}
return proxyproto.REJECT, errors.New(`upstream connection not trusted proxy_protocol_behavior is "deny_unauthorized"`)
2017-08-02 22:24:12 +00:00
},
}
default:
return listener, fmt.Errorf("unknown behavior type for proxy proto config")
}
return newLn, nil
}