Merge pull request #13 from danlsgiga/iptables-listen-destination-port

Add listen port option for NAT routing
This commit is contained in:
mayuresh82
2022-03-31 12:23:22 -07:00
committed by GitHub
3 changed files with 37 additions and 13 deletions

View File

@@ -52,6 +52,14 @@ GoCast supports consul for automatic service discovery and healthchecking. For t
If `gocast_monitor=consul` is specified, then GoCast uses the defined healthchecks in consul as the health monitors for the service. If `gocast_monitor=consul` is specified, then GoCast uses the defined healthchecks in consul as the health monitors for the service.
If `gocast_nat=protocol:listenPort:destinationPort` is specified, then GoCast will create NAT rules, via iptables, and map traffic destined to the assigned VIP and the specified `listenPort` to the physical IP and `destinationPort`.
Example: `gocast_nat=tcp:53:8053` and `gocast_nat=udp:53:8053`
Alternatively, if `gocast_nat=protocol:port` is specified, then GoCast will create NAT rules, via iptables, and map traffic destined to the assigned VIP and the specified `port` to the physical IP and `port`.
Example: `gocast_nat=tcp:53` and `gocast_nat=udp:53`
## Docker support ## Docker support
The docker image at mayuresh82/gocast can be used to run GoCast inside a container. In order for GoCast to manipulate the host network stack correctly, the container needs to run with NET_ADMIN capablity and host mode networking. For example: The docker image at mayuresh82/gocast can be used to run GoCast inside a container. In order for GoCast to manipulate the host network stack correctly, the container needs to run with NET_ADMIN capablity and host mode networking. For example:
``` ```
@@ -65,7 +73,7 @@ Certain orchestration solutions such as Nomad run the docker containers with pub
- Start the service container in host networking mode OR - Start the service container in host networking mode OR
- Register NAT rules for your service with GoCast for the required protocol/port(s). GoCast will then create iptables NAT rules that map traffic destined to the assigned VIP to the physical IP address. This is achieved by adding the `nat=protocol:port` tag(s) in consul or the http query. - Register NAT rules for your service with GoCast for the required protocol/port(s). GoCast will then create iptables NAT rules that map traffic destined to the assigned VIP to the physical IP address. This is achieved by adding the `nat=protocol:listenPort:destinationPort` in the http query or `gocast_nat=protocol:listenPort:destinationPort` tag(s) in consul, as shown in the Consul integration section above.
**Why not just use ExaBGP or something similar ?** **Why not just use ExaBGP or something similar ?**

View File

@@ -202,12 +202,18 @@ func (m *MonitorMgr) Remove(appName string) {
} }
for _, nat := range a.app.Nats { for _, nat := range a.app.Nats {
parts := strings.Split(nat, ":") parts := strings.Split(nat, ":")
if len(parts) != 2 { switch len(parts) {
case 3:
if err := natRule("D", a.app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1], parts[2]); err != nil {
glog.Errorf("Failed to remove app: %s: %v", a.app.Name, err)
}
case 2:
if err := natRule("D", a.app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1], parts[1]); err != nil {
glog.Errorf("Failed to remove app: %s: %v", a.app.Name, err)
}
default:
continue continue
} }
if err := natRule("D", a.app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1]); err != nil {
glog.Errorf("Failed to remove app: %s: %v", a.app.Name, err)
}
} }
} }
delete(m.monitors, appName) delete(m.monitors, appName)
@@ -248,12 +254,18 @@ func (m *MonitorMgr) checkCond(am *appMon) error {
} }
for _, nat := range app.Nats { for _, nat := range app.Nats {
parts := strings.Split(nat, ":") parts := strings.Split(nat, ":")
if len(parts) != 2 { switch len(parts) {
case 3:
if err := natRule("A", app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1], parts[2]); err != nil {
return err
}
case 2:
if err := natRule("A", app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1], parts[1]); err != nil {
return err
}
default:
continue continue
} }
if err := natRule("A", app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1]); err != nil {
return err
}
} }
if err := m.ctrl.Announce(app.Vip); err != nil { if err := m.ctrl.Announce(app.Vip); err != nil {
return fmt.Errorf("Failed to announce route: %v", err) return fmt.Errorf("Failed to announce route: %v", err)
@@ -315,10 +327,14 @@ func (m *MonitorMgr) CloseAll() {
deleteLoopback(am.app.Vip.Net) deleteLoopback(am.app.Vip.Net)
for _, nat := range am.app.Nats { for _, nat := range am.app.Nats {
parts := strings.Split(nat, ":") parts := strings.Split(nat, ":")
if len(parts) != 2 { switch len(parts) {
case 3:
natRule("D", am.app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1], parts[2])
case 2:
natRule("D", am.app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1], parts[1])
default:
continue continue
} }
natRule("D", am.app.Vip.Net.IP, m.ctrl.localIP, parts[0], parts[1])
} }
} }
} }

View File

@@ -86,10 +86,10 @@ func deleteLoopback(addr *net.IPNet) error {
return nil return nil
} }
func natRule(op string, vip, localAddr net.IP, protocol, port string) error { func natRule(op string, vip, localAddr net.IP, protocol, lport, dport string) error {
cmd := fmt.Sprintf( cmd := fmt.Sprintf(
"iptables -t nat -%s PREROUTING -p %s -d %s --dport %s -j DNAT --to-destination %s:%s", "iptables -t nat -%s PREROUTING -p %s -d %s --dport %s -j DNAT --to-destination %s:%s",
op, protocol, vip.String(), port, localAddr.String(), port, op, protocol, vip.String(), lport, localAddr.String(), dport,
) )
cmdList := getCmdList(cmd) cmdList := getCmdList(cmd)
_, err := exec.Command(execCmd, cmdList...).Output() _, err := exec.Command(execCmd, cmdList...).Output()