8d9a76c751
Rewrites the compiler from ~440 to ~1700 lines covering all major shorewall firewall features: loopback, conntrack fast-path, anti-spoof, DHCP, intra-zone, blacklist/whitelist, conntrack notrack, tunnels (13 types), rules with sections, DNAT/redirect, SNAT/masquerade, static NAT, policies with zone exclusions, MSS clamping, rate limiting, connection limiting, negated addresses, ICMP type matching, TCP RST reject, user/UID matching, mark match/set, NFQUEUE, NONAT, and policy-level rate/conn limiting. Adds full config types for all shorewall subsystems (mangle, accounting, maclist, netmap, providers, tunnels, conntrack, blrules, proxyarp/ndp, routes, tc, secmarks), shorewall migration tooling, expanded CLI commands, expression-level diff engine, and 49 unit tests.
63 lines
1.8 KiB
Go
63 lines
1.8 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
)
|
|
|
|
// StaticNAT defines a one-to-one NAT mapping between an external and internal address.
|
|
// All traffic to the external address is forwarded to the internal address and vice versa.
|
|
// DNAT rules take precedence over static NAT rules.
|
|
type StaticNAT struct {
|
|
// External IP address. Must not be the primary address of the interface.
|
|
// DNS names are not allowed.
|
|
External string `yaml:"external"`
|
|
|
|
// Interface that has the external address.
|
|
Interface string `yaml:"interface"`
|
|
|
|
// Internal IP address. DNS names are not allowed.
|
|
Internal string `yaml:"internal"`
|
|
|
|
// If true, NAT is effective from all hosts (not just those on the named interface).
|
|
AllInterfaces bool `yaml:"all_interfaces,omitempty"`
|
|
|
|
// If true, NAT is effective from the firewall system itself.
|
|
Local bool `yaml:"local,omitempty"`
|
|
|
|
Comment string `yaml:"comment,omitempty"`
|
|
}
|
|
|
|
func (c *Config) validateStaticNAT() error {
|
|
for i, n := range c.StaticNAT {
|
|
if n.External == "" {
|
|
return fmt.Errorf("nat[%d]: external address required", i)
|
|
}
|
|
if net.ParseIP(n.External) == nil {
|
|
return fmt.Errorf("nat[%d]: external must be an IP address, not a DNS name", i)
|
|
}
|
|
|
|
if n.Interface == "" {
|
|
return fmt.Errorf("nat[%d]: interface required", i)
|
|
}
|
|
ifaceFound := false
|
|
for _, iface := range c.Interfaces {
|
|
if iface.Interface == n.Interface || iface.PhysicalName() == n.Interface {
|
|
ifaceFound = true
|
|
break
|
|
}
|
|
}
|
|
if !ifaceFound {
|
|
return fmt.Errorf("nat[%d]: interface %q not defined in interfaces", i, n.Interface)
|
|
}
|
|
|
|
if n.Internal == "" {
|
|
return fmt.Errorf("nat[%d]: internal address required", i)
|
|
}
|
|
if net.ParseIP(n.Internal) == nil {
|
|
return fmt.Errorf("nat[%d]: internal must be an IP address, not a DNS name", i)
|
|
}
|
|
}
|
|
return nil
|
|
}
|