2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2017-08-02 22:24:12 +00:00
|
|
|
package proxyutil
|
|
|
|
|
|
|
|
import (
|
2022-03-08 17:13:00 +00:00
|
|
|
"errors"
|
2017-08-02 22:24:12 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"sync"
|
2018-06-16 22:21:33 +00:00
|
|
|
"time"
|
2017-08-02 22:24:12 +00:00
|
|
|
|
2021-07-16 00:17:31 +00:00
|
|
|
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
2017-08-02 22:24:12 +00:00
|
|
|
sockaddr "github.com/hashicorp/go-sockaddr"
|
2022-03-08 17:13:00 +00:00
|
|
|
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{
|
2022-03-09 17:14:30 +00:00
|
|
|
Listener: listener,
|
2022-03-08 17:13:00 +00:00
|
|
|
ReadHeaderTimeout: 10 * time.Second,
|
2017-08-02 22:24:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case "allow_authorized", "deny_unauthorized":
|
|
|
|
newLn = &proxyproto.Listener{
|
2022-03-09 17:14:30 +00:00
|
|
|
Listener: listener,
|
2022-03-08 17:13:00 +00:00
|
|
|
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 {
|
2022-03-08 17:13:00 +00:00
|
|
|
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) {
|
2022-03-08 17:13:00 +00:00
|
|
|
return proxyproto.USE, nil
|
2017-08-02 22:24:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.Behavior == "allow_authorized" {
|
2022-03-08 17:13:00 +00:00
|
|
|
return proxyproto.IGNORE, nil
|
2017-08-02 22:24:12 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 17:13:00 +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
|
|
|
|
}
|