//////////////////////////////////////////////////////////////////////// // 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 nearly-unlimited // most-rights-granted use/deployment/transfer/modification license. //////////////////////////////////////////////////////////////////////// package main import ( "fmt" //"kazoo_firewall_agent/cache" "log" "os" //"os/signal" "strings" //"syscall" "time" ) const appnameFull string = "Kazoo Firewall Agent" const appname string = "kazoo_firewall_agent" const version string = "1.0" const serverVersion string = "RuhNet " + appname + " v" + version const website string = "https://ruhnet.co" var startupTime time.Time var myHostname, myHostnameShort string const banner = ` --⟶____ __ _ _ __ -⟶/ ___\ __ __/ /_ / \ / /__ __/ /_ ⟶/ /_/ // /_/ / _ \/ / \/ //__\_ __/ /_/ \_\\ ___/_/ /_/_/ \__/ \__,/_/ %s _____________________________________________________ ` var ipcache *TTLCache var done = make(chan bool, 1) var portProtos []PortProto type PortProto struct { Port string Proto string } type AppConfig struct { ServerType string `json:"server_type" env:"SERVER_TYPE" default:"freeswitch"` AmqpURI string `json:"amqp_uri" env:"AMQP_URI" default:"amqp://guest:guest@localhost:5672"` AmqpExch string `json:"amqp_exchange" env:"AMQP_EXCH" default:"call_shield"` AmqpSubExch string `json:"amqp_sub_exchange" env:"AMQP_SUB_EXCH" default:""` AmqpPubExch string `json:"amqp_pub_exchange" env:"AMQP_PUB_EXCH" default:""` AmqpExchType string `json:"amqp_exchange_type" env:"AMQP_EXCH_TYPE" default:"topic"` AmqpDirectRoutingKey string `json:"amqp_direct_routing_key" env:"AMQP_DIRECT_ROUTING_KEY" default:""` //call_shield.{hostname}.*.* AmqpSubRoutingKey string `json:"amqp_sub_routing_key" env:"AMQP_SUB_ROUTING_KEY" default:""` //"call_shield.{server_type}.firewall.*" AmqpPubRoutingKey string `json:"amqp_pub_routing_key" env:"AMQP_PUB_ROUTING_KEY" default:"call_shield.test"` AmqpWorkers int `json:"amqp_workers" env:"AMQP_WORKERS" default:"4"` PubMessageFile string `json:"pub_message_file" env:"PUB_MSG_FILE" default:"/tmp/message.json"` Ports string `json:"ports" env:"PORTS" default:"11000/udp,11000,11001/tcp,16384-32768/udp"` FilterEvtCat string `json:"filter_event_category" env:"FLT_EVT_CAT" default:"*"` //allow comma separated string for multiple FilterEvtName string `json:"filter_event_name" env:"FLT_EVT_NAME" default:"*"` FilterEvtAppName string `json:"filter_event_appname" env:"FLT_EVT_APPNAME" default:"*"` CacheTimeout int64 `json:"cache_timeout_sec" env:"CACHE_TIMEOUT" default:"43200"` //43200 is 12hr FirewallType string `json:"firewall_type" env:"FIREWALL_ZONE" default:"firewalld"` //firewalld, iptables FirewallZone string `json:"firewall_zone" env:"FIREWALL_ZONE" default:"SIPFS"` LogFile string `json:"log_file" env:"LOG_FILE" default:"/var/log/kazoo_firewall_agent.log"` LogLevel int `json:"log_level" env:"LOG_LEVEL" default:"5"` } func main() { var err error startupTime = time.Now() ///////////////////////////////////////////// // Setup initConfig() fmt.Println("Configuration OK, starting " + appname + "...") logit(5, "Configuration OK, starting "+appname+"...") ///////////////////////////////////////////// // Logging appLogFile, err := os.OpenFile(appconf.LogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664) if err != nil { log.Println("Could not open log file: " + appconf.LogFile + "\n" + err.Error()) appLogFile, err = os.OpenFile("/tmp/"+appname+".log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664) if err != nil { fmt.Println("Can't open even /tmp log file!\n" + err.Error()) log.Fatal("Can't open even /tmp log file!\n" + err.Error()) } } defer appLogFile.Close() //set other logging to same file log.SetOutput(appLogFile) //Startup Banner fmt.Printf(banner, website) fmt.Printf(serverVersion + "\n\n") logit(5, appname+"v"+version+" starting up... ") logit(5, fmt.Sprintf("Logging with level: %d", appconf.LogLevel)) //Hostname myHostname, err = os.Hostname() logit(5, "Detecting my hostname... "+myHostname) if err != nil { fmt.Println("Hostname could not be auto-detected from system: " + err.Error()) log.Fatal("Hostname could not be auto-detected from system: " + err.Error()) } myHostnameShort = strings.SplitN(myHostname, ".", 2)[0] //fmt.Println() //create the IP address cache with expiry and function to run when cached entry expires if shouldAddPermanently() { ipcache = NewTTL(appconf.CacheTimeout, firewallDeleteCacheOnly) } else { ipcache = NewTTL(appconf.CacheTimeout, firewallDelete) } if appconf.FirewallType == "firewalld" { logit(5, "reloading FirewallD...") err = reload() //reload firewalld to reset firewall state if err != nil { fmt.Println("FirewallD could not be reloaded! (Is firewalld running?): " + err.Error()) log.Fatal("FirewallD could not be reloaded. (Is firewalld running?): " + err.Error()) } err = maybeSetupZone(appconf.FirewallZone) //reload firewalld to reset firewall state if err != nil { fmt.Println("Firewall zone '" + appconf.FirewallZone + "' could not be created. (Is firewalld running?): " + err.Error()) log.Fatal("Firewall zone '" + appconf.FirewallZone + "' could not be created. (Is firewalld running?): " + err.Error()) } } amqp() //this func will block the main thread, until receiving on the 'done' channel. }