Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proxy: support dynamic port number #289

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions modules/l4proxy/healthchecks.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ func (h *Handler) doActiveHealthCheckForAllHosts() {
// fails.
func (h *Handler) doActiveHealthCheck(p *peer) error {
addr := p.address
if addr == nil {
return nil
}

// adjust the port, if configured to be different
if h.HealthChecks.Active.Port > 0 {
Expand Down
18 changes: 13 additions & 5 deletions modules/l4proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,21 @@ func (h *Handler) dialPeers(upstream *Upstream, repl *caddy.Replacer, down *laye
var upConns []net.Conn

for _, p := range upstream.peers {
hostPort := repl.ReplaceAll(p.address.JoinHostPort(0), "")
hostPort := repl.ReplaceAll(p.dialAddr, "")
addr := p.address

var up net.Conn
var err error

if addr == nil {
addr, err = ParseAddress(hostPort)
if err != nil {
return nil, err
}
}

if upstream.TLS == nil {
up, err = net.Dial(p.address.Network, hostPort)
up, err = net.Dial(addr.Network, hostPort)
} else {
// the prepared config could be nil if user enabled but did not customize TLS,
// in which case we adopt the downstream client's TLS ClientHello for ours;
Expand All @@ -218,7 +226,7 @@ func (h *Handler) dialPeers(upstream *Upstream, repl *caddy.Replacer, down *laye
hellos[0].FillTLSClientConfig(tlsCfg)
}
}
up, err = tls.Dial(p.address.Network, hostPort, tlsCfg)
up, err = tls.Dial(addr.Network, hostPort, tlsCfg)
}
h.logger.Debug("dial upstream",
zap.String("remote", down.RemoteAddr().String()),
Expand Down Expand Up @@ -346,7 +354,7 @@ func (h *Handler) countFailure(p *peer) {
err := p.countFail(1)
if err != nil {
h.HealthChecks.Passive.logger.Error("could not count failure",
zap.String("peer_address", p.address.String()),
zap.String("peer_address", p.dialAddr),
zap.Error(err))
return
}
Expand All @@ -362,7 +370,7 @@ func (h *Handler) countFailure(p *peer) {
err := p.countFail(-1)
if err != nil {
h.HealthChecks.Passive.logger.Error("could not forget failure",
zap.String("peer_address", p.address.String()),
zap.String("peer_address", p.dialAddr),
zap.Error(err))
}
}(failDuration)
Expand Down
36 changes: 25 additions & 11 deletions modules/l4proxy/upstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,23 @@ import (
"github.com/mholt/caddy-l4/layer4"
)

func ParseAddress(addr string) (*caddy.NetworkAddress, error) {
address, err := caddy.ParseNetworkAddress(addr)
if err != nil {
return nil, err
}
if address.PortRangeSize() != 1 {
return nil, fmt.Errorf("%s: port ranges not currently supported", addr)
}
return &address, nil
}

// UpstreamPool is a collection of upstreams.
type UpstreamPool []*Upstream

// Upstream represents a proxy upstream.
type Upstream struct {
// The network addresses to dial. Supports placeholders, but not port
// The network addresses to dial. Supports placeholders
// ranges currently (each address must be exactly 1 socket).
Dial []string `json:"dial,omitempty"`

Expand Down Expand Up @@ -63,17 +74,19 @@ func (u *Upstream) provision(ctx caddy.Context, h *Handler) error {
// in Handler.dialPeers. E.g. {l4.tls.server_name}:443 will allow for dynamic TLS SNI based upstreams.
replDialAddr := repl.ReplaceKnown(dialAddr, "")

// parse and validate address
addr, err := caddy.ParseNetworkAddress(replDialAddr)
if err != nil {
return err
}
if addr.PortRangeSize() != 1 {
return fmt.Errorf("%s: port ranges not currently supported", replDialAddr)
// create or load peer info
p := &peer{dialAddr: replDialAddr}
// parse and validate address if upstream not dynamic
// If upstream address contains placeholders, skip parsing here
// then do this after replacing all placeholders in Handler.dialPeers.
if !(strings.Contains(p.dialAddr, "{") && strings.Contains(p.dialAddr, "}")) {
address, err := ParseAddress(p.dialAddr)
if err != nil {
return err
}
p.address = address
}

// create or load peer info
p := &peer{address: addr}
existingPeer, loaded := peers.LoadOrStore(dialAddr, p) // peers are deleted in Handler.Cleanup
if loaded {
p = existingPeer.(*peer)
Expand Down Expand Up @@ -387,7 +400,8 @@ type peer struct {
numConns int32
unhealthy int32
fails int32
address caddy.NetworkAddress
address *caddy.NetworkAddress
dialAddr string
}

// getNumConns returns the number of active connections with the peer.
Expand Down