Fix: Add a way to differentiate between bind and local address

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2023-11-14 15:55:32 +01:00
parent 14e437b11e
commit e52865a029
Signed by: luzifer
GPG key ID: D91C3E91E4CAD6F5
4 changed files with 31 additions and 22 deletions

View file

@ -63,28 +63,34 @@ healthCheck:
path: /healthz path: /healthz
tls: true tls: true
# Local Address and Port describes the IP and Port to bind the service # Bind Address and Port describes the IP and Port to bind the service
# to. The Address given is used for the SNAT and therefore should for # to.
# example be the public IP of the machine bindAddr: 203.0.113.1
localAddr: 203.0.113.1 bindPort: 443
localPort: 443
# Proto describes which protocol should be routed (defaults to tcp)
proto: tcp
# Targets is a list of routing targets which are checked for their # Targets is a list of routing targets which are checked for their
# liveness status and if they are live, they are included in the NAT # liveness status and if they are live, they are included in the NAT
# rulesets. # rulesets.
# Each target consists of an Address, a Port and a Weight. The weight # Each target consists of two Addresses, a Port and a Weight. The weight
# is defined as an integer and increases / decreases the percentage # is defined as an integer and increases / decreases the percentage
# of the traffic that specific target will receive. (For example # of the traffic that specific target will receive. (For example
# setting all weights to 1 will distribute the traffic equally between # setting all weights to 1 will distribute the traffic equally between
# them, setting one to 2 will double the traffic to that target.) # them, setting one to 2 will double the traffic to that target.)
# The localAddr is used for the SNAT to map the source IP.
targets: targets:
- addr: 10.1.2.4 - addr: 10.1.2.4
localAddr: 10.1.2.1
port: 443 port: 443
weight: 1 weight: 1
- addr: 10.1.2.5 - addr: 10.1.2.5
localAddr: 10.1.2.1
port: 443 port: 443
weight: 1 weight: 1
- addr: 10.1.2.6 - addr: 10.1.2.6
localAddr: 10.1.2.1
port: 443 port: 443
weight: 1 weight: 1
``` ```

View file

@ -23,9 +23,9 @@ type (
Service struct { Service struct {
Name string `yaml:"name"` Name string `yaml:"name"`
HealthCheck ServiceHealthCheck `yaml:"healthCheck"` HealthCheck ServiceHealthCheck `yaml:"healthCheck"`
LocalAddr string `yaml:"localAddr"` BindAddr string `yaml:"bindAddr"`
LocalPort int `yaml:"localPort"` BindPort int `yaml:"bindPort"`
LocalProto string `yaml:"localProto"` Proto string `yaml:"proto"`
Targets []Target `yaml:"targets"` Targets []Target `yaml:"targets"`
} }
@ -40,9 +40,10 @@ type (
// Target represents a load-balancing target to route the traffic // Target represents a load-balancing target to route the traffic
// to in case it is deemed alive // to in case it is deemed alive
Target struct { Target struct {
Addr string `yaml:"addr"` Addr string `yaml:"addr"`
Port int `yaml:"port"` LocalAddr string `yaml:"localAddr"`
Weight int `yaml:"weight"` Port int `yaml:"port"`
Weight int `yaml:"weight"`
} }
) )
@ -73,12 +74,12 @@ func Load(fn string) (cf File, err error) {
return cf, nil return cf, nil
} }
// Proto evaluates the LocalProto and returns tcp if empty // Protocol evaluates the Proto and returns tcp if empty
func (s Service) Proto() string { func (s Service) Protocol() string {
if s.LocalProto == "" { if s.Proto == "" {
return "tcp" return "tcp"
} }
return s.LocalProto return s.Proto
} }
func (t Target) String() string { return fmt.Sprintf("%s:%d", t.Addr, t.Port) } func (t Target) String() string { return fmt.Sprintf("%s:%d", t.Addr, t.Port) }

View file

@ -34,8 +34,9 @@ type (
// with random distribution and given probability // with random distribution and given probability
NATTarget struct { NATTarget struct {
Addr string Addr string
BindAddr string
BindPort int
LocalAddr string LocalAddr string
LocalPort int
Port int Port int
Proto string Proto string
Weight float64 Weight float64
@ -182,8 +183,8 @@ func (c *Client) buildServiceTable(service string, cType chainType) (rules [][]s
"--probability", strconv.FormatFloat(nt.Weight/weightLeft, 'f', probPrecision, probBitsize), "--probability", strconv.FormatFloat(nt.Weight/weightLeft, 'f', probPrecision, probBitsize),
"-p", nt.Proto, "-p", nt.Proto,
"-d", nt.LocalAddr, "-d", nt.BindAddr,
"--dport", strconv.Itoa(nt.LocalPort), "--dport", strconv.Itoa(nt.BindPort),
"-j", "DNAT", "-j", "DNAT",
"--to-destination", fmt.Sprintf("%s:%d", nt.Addr, nt.Port), "--to-destination", fmt.Sprintf("%s:%d", nt.Addr, nt.Port),

View file

@ -67,11 +67,12 @@ func (m Monitor) updateRoutingTargets(checker healthcheck.Checker) (err error) {
tgt := iptables.NATTarget{ tgt := iptables.NATTarget{
Addr: t.Addr, Addr: t.Addr,
LocalAddr: m.svc.LocalAddr, BindAddr: m.svc.BindAddr,
LocalPort: m.svc.LocalPort, BindPort: m.svc.BindPort,
LocalAddr: t.LocalAddr,
Port: t.Port, Port: t.Port,
Weight: float64(t.Weight), Weight: float64(t.Weight),
Proto: m.svc.Proto(), Proto: m.svc.Protocol(),
} }
if err := checker.Check(m.svc.HealthCheck.Settings, t); err != nil { if err := checker.Check(m.svc.HealthCheck.Settings, t); err != nil {