Compare commits
1 Commits
config_rel
...
iptables_n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
256afcbd97 |
11
README.md
11
README.md
@@ -74,11 +74,20 @@ kill -HUP $(pidof gocast)
|
|||||||
**What gets reloaded:**
|
**What gets reloaded:**
|
||||||
- BGP configuration (peers, AS numbers, MD5 passwords, communities)
|
- BGP configuration (peers, AS numbers, MD5 passwords, communities)
|
||||||
- Application definitions (add/remove/update apps)
|
- Application definitions (add/remove/update apps)
|
||||||
- Agent settings (Consul, timers, intervals)
|
- Agent settings (Consul, timers, intervals, iptables binary)
|
||||||
|
|
||||||
**Important:** Reloading BGP configuration causes existing BGP sessions to be restarted, resulting in brief routing interruption. Routes are automatically re-announced after reload.
|
**Important:** Reloading BGP configuration causes existing BGP sessions to be restarted, resulting in brief routing interruption. Routes are automatically re-announced after reload.
|
||||||
Consul-discovered apps are not removed during reload.
|
Consul-discovered apps are not removed during reload.
|
||||||
|
|
||||||
|
## Iptables Configuration
|
||||||
|
|
||||||
|
On modern Linux systems using nftables, you need to configure gocast to use `iptables-nft` instead of the legacy `iptables` binary (default):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
agent:
|
||||||
|
iptables_binary: iptables-nft
|
||||||
|
```
|
||||||
|
|
||||||
## 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:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ agent:
|
|||||||
consul_query_interval: 5m
|
consul_query_interval: 5m
|
||||||
# token to authenticate client if consul requires it
|
# token to authenticate client if consul requires it
|
||||||
consul_token: 00000000-0000-0000-0000-000000000000
|
consul_token: 00000000-0000-0000-0000-000000000000
|
||||||
|
# iptables binary to use for NAT rules (default: iptables)
|
||||||
|
# Use "iptables-nft" on modern systems with nftables
|
||||||
|
# iptables_binary: iptables-nft
|
||||||
|
|
||||||
bgp:
|
bgp:
|
||||||
local_as: 12345
|
local_as: 12345
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type AgentConfig struct {
|
|||||||
ConsulAddr string `yaml:"consul_addr"`
|
ConsulAddr string `yaml:"consul_addr"`
|
||||||
ConsulQueryInterval time.Duration `yaml:"consul_query_interval"`
|
ConsulQueryInterval time.Duration `yaml:"consul_query_interval"`
|
||||||
ConsulToken string `yaml:"consul_token"`
|
ConsulToken string `yaml:"consul_token"`
|
||||||
|
IptablesBinary string `yaml:"iptables_binary"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PeerConfig struct {
|
type PeerConfig struct {
|
||||||
|
|||||||
@@ -98,6 +98,11 @@ func NewMonitor(config *c.Config) *MonitorMgr {
|
|||||||
if config.Agent.CleanupTimer == 0 {
|
if config.Agent.CleanupTimer == 0 {
|
||||||
config.Agent.CleanupTimer = defaultCleanupTimer
|
config.Agent.CleanupTimer = defaultCleanupTimer
|
||||||
}
|
}
|
||||||
|
// Set iptables binary (defaults to "iptables" if not specified)
|
||||||
|
if config.Agent.IptablesBinary == "" {
|
||||||
|
config.Agent.IptablesBinary = "iptables"
|
||||||
|
}
|
||||||
|
SetIptablesBinary(config.Agent.IptablesBinary)
|
||||||
mon.config = config
|
mon.config = config
|
||||||
// add apps defined in config
|
// add apps defined in config
|
||||||
for _, a := range config.Apps {
|
for _, a := range config.Apps {
|
||||||
@@ -356,6 +361,15 @@ func (m *MonitorMgr) Reload(configPath string) error {
|
|||||||
if newConfig.Agent.CleanupTimer == 0 {
|
if newConfig.Agent.CleanupTimer == 0 {
|
||||||
newConfig.Agent.CleanupTimer = defaultCleanupTimer
|
newConfig.Agent.CleanupTimer = defaultCleanupTimer
|
||||||
}
|
}
|
||||||
|
if newConfig.Agent.IptablesBinary == "" {
|
||||||
|
newConfig.Agent.IptablesBinary = "iptables"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update iptables binary if changed
|
||||||
|
if m.config.Agent.IptablesBinary != newConfig.Agent.IptablesBinary {
|
||||||
|
glog.Infof("Iptables binary changed from %s to %s", m.config.Agent.IptablesBinary, newConfig.Agent.IptablesBinary)
|
||||||
|
SetIptablesBinary(newConfig.Agent.IptablesBinary)
|
||||||
|
}
|
||||||
|
|
||||||
// Check if BGP configuration has changed
|
// Check if BGP configuration has changed
|
||||||
bgpChanged := m.bgpConfigChanged(m.config.Bgp, newConfig.Bgp)
|
bgpChanged := m.bgpConfigChanged(m.config.Bgp, newConfig.Bgp)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var execCmd = "bash"
|
var execCmd = "bash"
|
||||||
|
var iptablesBinary = "iptables"
|
||||||
|
|
||||||
func getCmdList(mainCmd string) []string {
|
func getCmdList(mainCmd string) []string {
|
||||||
cmdList := []string{}
|
cmdList := []string{}
|
||||||
@@ -88,8 +89,8 @@ func deleteLoopback(addr *net.IPNet) error {
|
|||||||
|
|
||||||
func natRule(op string, vip, localAddr net.IP, protocol, lport, dport 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",
|
"%s -t nat -%s PREROUTING -p %s -d %s --dport %s -j DNAT --to-destination %s:%s",
|
||||||
op, protocol, vip.String(), lport, localAddr.String(), dport,
|
iptablesBinary, 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()
|
||||||
@@ -98,3 +99,10 @@ func natRule(op string, vip, localAddr net.IP, protocol, lport, dport string) er
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIptablesBinary sets the iptables binary to use for NAT rules
|
||||||
|
func SetIptablesBinary(binary string) {
|
||||||
|
if binary != "" {
|
||||||
|
iptablesBinary = binary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,6 +43,71 @@ func TestAddLoopback(t *testing.T) {
|
|||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetIptablesBinary(t *testing.T) {
|
||||||
|
a := assert.New(t)
|
||||||
|
|
||||||
|
// Save original value
|
||||||
|
originalBinary := iptablesBinary
|
||||||
|
defer func() {
|
||||||
|
iptablesBinary = originalBinary
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Test setting custom binary
|
||||||
|
SetIptablesBinary("iptables-nft")
|
||||||
|
a.Equal("iptables-nft", iptablesBinary)
|
||||||
|
|
||||||
|
// Test setting back to default
|
||||||
|
SetIptablesBinary("iptables")
|
||||||
|
a.Equal("iptables", iptablesBinary)
|
||||||
|
|
||||||
|
// Test that empty string doesn't change the value
|
||||||
|
SetIptablesBinary("iptables-custom")
|
||||||
|
a.Equal("iptables-custom", iptablesBinary)
|
||||||
|
SetIptablesBinary("")
|
||||||
|
a.Equal("iptables-custom", iptablesBinary, "Empty string should not change the binary")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNatRuleCommandFormat(t *testing.T) {
|
||||||
|
a := assert.New(t)
|
||||||
|
|
||||||
|
// Save original values
|
||||||
|
originalBinary := iptablesBinary
|
||||||
|
originalExecCmd := execCmd
|
||||||
|
defer func() {
|
||||||
|
iptablesBinary = originalBinary
|
||||||
|
execCmd = originalExecCmd
|
||||||
|
}()
|
||||||
|
|
||||||
|
vip := net.ParseIP("192.0.2.1")
|
||||||
|
localAddr := net.ParseIP("10.0.0.1")
|
||||||
|
|
||||||
|
// Test with default iptables
|
||||||
|
SetIptablesBinary("iptables")
|
||||||
|
err := natRule("A", vip, localAddr, "tcp", "80", "8080")
|
||||||
|
// We expect this to fail in test environment, but we can check the error message
|
||||||
|
// contains our command
|
||||||
|
if err != nil {
|
||||||
|
a.Contains(err.Error(), "iptables -t nat -A PREROUTING")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with iptables-nft
|
||||||
|
SetIptablesBinary("iptables-nft")
|
||||||
|
err = natRule("A", vip, localAddr, "tcp", "80", "8080")
|
||||||
|
if err != nil {
|
||||||
|
a.Contains(err.Error(), "iptables-nft -t nat -A PREROUTING")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with custom binary path
|
||||||
|
SetIptablesBinary("/usr/sbin/iptables")
|
||||||
|
err = natRule("D", vip, localAddr, "udp", "53", "5353")
|
||||||
|
if err != nil {
|
||||||
|
a.Contains(err.Error(), "/usr/sbin/iptables -t nat -D PREROUTING")
|
||||||
|
a.Contains(err.Error(), "udp")
|
||||||
|
a.Contains(err.Error(), "53")
|
||||||
|
a.Contains(err.Error(), "5353")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
switch os.Getenv("test_name") {
|
switch os.Getenv("test_name") {
|
||||||
case "test_gateway":
|
case "test_gateway":
|
||||||
|
|||||||
Reference in New Issue
Block a user