From fbe05cff391babba40651fc3a8afc93421ac1f27 Mon Sep 17 00:00:00 2001 From: Ruel Tmeizeh - RuhNet Date: Sat, 29 Nov 2025 12:32:24 -0500 Subject: [PATCH] Support both temporary and permanent firewall, depending on server type. --- firewall.go | 87 ++++++++++++++++++++++++++++++++++++++++++----------- main.go | 10 ++++-- 2 files changed, 77 insertions(+), 20 deletions(-) diff --git a/firewall.go b/firewall.go index 1af8ed9..67aba1b 100644 --- a/firewall.go +++ b/firewall.go @@ -1,4 +1,4 @@ -// This file copyright 2024, PBX.com LLC +// This file copyright 2024-2025, PBX.com LLC package main @@ -12,33 +12,37 @@ import ( ) func firewall(action, ipaddr string, inputports interface{}) (err error) { + return firewallWithTimeout(action, ipaddr, inputports, appconf.CacheTimeout) +} + +func firewallWithTimeout(action, ipaddr string, inputports interface{}, timeout int64) (err error) { switch p := inputports.(type) { case []interface{}: for _, porti := range p { switch port := porti.(type) { case string: - firewallAction(action, ipaddr, port) + firewallAction(action, ipaddr, port, timeout) case float64: - firewallAction(action, ipaddr, strconv.Itoa(int(port))) + firewallAction(action, ipaddr, strconv.Itoa(int(port)), timeout) case int64: - firewallAction(action, ipaddr, strconv.Itoa(int(port))) + firewallAction(action, ipaddr, strconv.Itoa(int(port)), timeout) case int: - firewallAction(action, ipaddr, strconv.Itoa(port)) + firewallAction(action, ipaddr, strconv.Itoa(port), timeout) } } case []string: for _, port := range p { - firewallAction(action, ipaddr, port) + firewallAction(action, ipaddr, port, timeout) } case float64: - firewallAction(action, ipaddr, strconv.Itoa(int(p))) + firewallAction(action, ipaddr, strconv.Itoa(int(p)), timeout) case string: splitPorts := strings.Split(p, ",") for _, port := range splitPorts { - firewallAction(action, ipaddr, port) + firewallAction(action, ipaddr, port, timeout) } case nil: - firewallAction(action, ipaddr, "") + firewallAction(action, ipaddr, "", timeout) default: } return nil @@ -71,10 +75,10 @@ func parsePortProto(p string) PortProto { return pp } -func firewallAction(action, ipaddr string, portstring string) (err error) { +func firewallAction(action, ipaddr, portstring string, timeout int64) (err error) { switch action { case "firewall_add": - err = firewallAdd(ipaddr, portstring) + err = firewallAdd(ipaddr, portstring, timeout) case "firewall_remove": err = firewallDelete(ipaddr, portstring) } @@ -82,12 +86,16 @@ func firewallAction(action, ipaddr string, portstring string) (err error) { return err } -func firewallAdd(ipaddr, portstring string) error { +func firewallAdd(ipaddr, portstring string, timeout int64) error { var pp PortProto pp = parsePortProto(portstring) zone := determineZone(ipaddr, pp) - logit(5, "Firewall adding to zone '"+zone+"': "+ipaddr+":"+pp.Port+"/"+pp.Proto) + if len(pp.Port) > 0 { + logit(5, "Firewall adding to zone '"+zone+"': "+ipaddr+":"+pp.Port+"/"+pp.Proto) + } else { + logit(5, "Firewall adding to zone '"+zone+"': "+ipaddr) + } //ipcache.Set(ipaddr+":"+pp.Port+"/"+pp.Proto, zone, time.Duration(appconf.CacheTimeout) * time.Second) if len(pp.Port) > 0 { @@ -101,20 +109,43 @@ func firewallAdd(ipaddr, portstring string) error { //if it's already cached, then don't add it, just refresh the expiry time and return _, alreadyExists := ipcache.Get(ipaddr) if alreadyExists { - ipcache.Set(ipaddr, zone, time.Duration(appconf.CacheTimeout)*time.Second) + ipcache.Set(ipaddr, zone, time.Duration(timeout)*time.Second) return nil } fwOutput, err := exec.Command("firewall-cmd", "--zone="+zone, "--add-source="+ipaddr).CombinedOutput() if err != nil { logit(3, "Error executing firewall-cmd: "+err.Error()+" OUTPUT: "+string(fwOutput)) - return errors.New("Error executing firewall-cmd: " + err.Error()) + return errors.New("Error executing current firewall-cmd: " + err.Error()) + } + ipcache.Set(ipaddr, zone, time.Duration(timeout)*time.Second) + + // maybe add permanently also + if shouldAddPermanently() { + fwOutput, err = exec.Command("firewall-cmd", "--permanent", "--zone="+zone, "--add-source="+ipaddr).CombinedOutput() + if err != nil { + logit(3, "Error executing firewall-cmd --permanent: "+err.Error()+" OUTPUT: "+string(fwOutput)) + return errors.New("Error executing permanent firewall-cmd: " + err.Error()) + } + if len(pp.Port) > 0 { + err := maybeAddPort(zone, pp, true) + if err != nil { + logit(3, err.Error()) + return err + } + } } - ipcache.Set(ipaddr, zone, time.Duration(appconf.CacheTimeout)*time.Second) return nil } +func shouldAddPermanently() bool { + if appconf.ServerType == "ephemeral" || appconf.ServerType == "freeswitch" { + return false + } + return true +} + func firewallDelete(ipaddr, portstring string) error { var pp PortProto pp = parsePortProto(portstring) @@ -131,6 +162,27 @@ func firewallDelete(ipaddr, portstring string) error { return errors.New("Error executing firewall-cmd: " + err.Error()) } + // maybe remove permanently also + if shouldAddPermanently() { + fwOutput, err = exec.Command("firewall-cmd", "--permanent", "--zone="+zone, "--remove-source="+ipaddr).CombinedOutput() + if err != nil { + logit(3, "Error executing firewall-cmd --permanent: "+err.Error()+" OUTPUT: "+string(fwOutput)) + return errors.New("Error executing firewall-cmd --permanent: " + err.Error()) + } + } + + return nil +} + +func firewallDeleteCacheOnly(ipaddr, portstring string) error { + var pp PortProto + pp = parsePortProto(portstring) + zone := determineZone(ipaddr, pp) + + logit(5, "removing from cache: '"+zone+"' "+ipaddr) + + ipcache.Remove(ipaddr) + return nil } @@ -152,6 +204,7 @@ func maybeAddPort(zone string, pp PortProto, permanent bool) error { return nil } + func addZonePort(zone, port string, permanent bool) error { cmd := exec.Command("firewall-cmd", "--zone="+zone, "--add-port="+port) if permanent { @@ -233,7 +286,7 @@ func reload() error { func determineZone(ipaddr string, pp PortProto) string { var zone string - logit(7, "Determine zone for ipaddr '"+ipaddr+"'...") + //logit(7, "Determine zone for ipaddr '"+ipaddr+"'...") //do stuff diff --git a/main.go b/main.go index a7e9409..799c9b9 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,8 @@ //////////////////////////////////////////////////////////////////////// -// KazooFirewallAgent (c) 2024, RuhNet, All Rights Reserved, except +// KazooFirewallAgent (c) 2024-2025, RuhNet, All Rights Reserved, except // for firewall.go, which is copyright PBX.com LLC // Author: Ruel Tmeizeh, RuhNet www.ruhnet.co -// Dual-Licensed to PBX.com LLC under a non-exclusive unlimited +// Dual-Licensed to PBX.com LLC under a non-exclusive nearly-unlimited // most-rights-granted use/deployment/transfer/modification license. //////////////////////////////////////////////////////////////////////// package main @@ -114,7 +114,11 @@ func main() { //fmt.Println() //create the IP address cache with expiry and function to run when cached entry expires - ipcache = NewTTL(appconf.CacheTimeout, firewallDelete) + if shouldAddPermanently() { + ipcache = NewTTL(appconf.CacheTimeout, firewallDeleteCacheOnly) + } else { + ipcache = NewTTL(appconf.CacheTimeout, firewallDelete) + } if appconf.FirewallType == "firewalld" { logit(5, "reloading FirewallD...")