|
|
////////////////////////////////////////////////////////////////////////
|
|
|
// 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.
|
|
|
}
|