Make the user interface a module, Rework modules

This commit is contained in:
Kioubit 2021-12-27 11:24:21 -05:00
parent 0f580cbbbd
commit 6ebee06861
5 changed files with 288 additions and 191 deletions

142
config.go
View File

@ -10,24 +10,6 @@ import (
"strings" "strings"
) )
type configResponder struct {
Iface string
Filter string
autosense string
instance *pndp.ResponderObj
}
type configProxy struct {
Iface1 string
Iface2 string
Filter string
autosense string
instance *pndp.ProxyObj
}
var allResponders []*configResponder
var allProxies []*configProxy
func readConfig(dest string) { func readConfig(dest string) {
file, err := os.Open(dest) file, err := os.Open(dest)
if err != nil { if err != nil {
@ -52,120 +34,40 @@ func readConfig(dest string) {
continue continue
} }
if strings.HasPrefix(line, "responder") && strings.Contains(line, "{") { if strings.HasSuffix(line, "{") {
obj := configResponder{} option := strings.TrimSuffix(strings.TrimSpace(line), "{")
filter := "" option = strings.TrimSpace(option)
module, command := modules.GetCommand(option)
var lines = make([]string, 0)
if module != nil {
for { for {
if !scanner.Scan() { if !scanner.Scan() {
break break
} }
line = strings.TrimSpace(scanner.Text()) line := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, "iface") { if strings.Contains(line, "}") {
obj.Iface = strings.TrimSpace(strings.TrimPrefix(line, "iface"))
}
if strings.HasPrefix(line, "filter") {
filter += strings.TrimSpace(strings.TrimPrefix(line, "filter")) + ";"
if strings.Contains(line, ";") {
panic("Invalid config file syntax")
}
}
if strings.HasPrefix(line, "autosense") {
obj.autosense = strings.TrimSpace(strings.TrimPrefix(line, "autosense"))
}
if strings.HasPrefix(line, "}") {
obj.Filter = strings.TrimSuffix(filter, ";")
break break
} }
lines = append(lines, line)
}
modules.ExecuteInit(module, modules.CallbackInfo{
CallbackType: modules.Config,
Command: command,
Arguments: lines,
})
}
} }
allResponders = append(allResponders, &obj)
} else if strings.HasPrefix(line, "proxy") && strings.Contains(line, "{") {
obj := configProxy{}
filter := ""
for {
if !scanner.Scan() {
break
}
line = strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, "iface1") {
obj.Iface1 = strings.TrimSpace(strings.TrimPrefix(line, "iface1"))
}
if strings.HasPrefix(line, "iface2") {
obj.Iface2 = strings.TrimSpace(strings.TrimPrefix(line, "iface2"))
}
if strings.HasPrefix(line, "filter") {
filter += strings.TrimSpace(strings.TrimPrefix(line, "filter")) + ";"
if strings.Contains(line, ";") {
panic("Invalid config file syntax")
}
}
if strings.HasPrefix(line, "autosense") {
obj.autosense = strings.TrimSpace(strings.TrimPrefix(line, "autosense"))
}
if strings.HasPrefix(line, "}") {
obj.Filter = strings.TrimSuffix(filter, ";")
break
}
if strings.HasPrefix(line, "}") {
break
}
}
allProxies = append(allProxies, &obj)
} else if strings.Contains(line, "{") {
option := strings.TrimSuffix(strings.TrimSpace(line), "{")
option = strings.TrimSpace(option)
if modules.ModuleList != nil {
for i := range modules.ModuleList {
for d := range (*modules.ModuleList[i]).Option {
if (*modules.ModuleList[i]).Option[d].Option == option {
var lines []string
for {
if !scanner.Scan() {
break
}
line = strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, "}") {
break
}
lines = append(lines, line)
}
(*modules.ModuleList[i]).Callback(modules.Callback{
CallbackType: modules.Config,
Option: option,
Arguments: lines,
})
return
}
}
}
}
} }
if modules.ExistsBlockingModule() {
modules.ExecuteComplete()
waitForSignal()
modules.ShutdownAll()
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
log.Fatal(err) panic(err)
}
for _, n := range allProxies {
o := pndp.NewProxy(n.Iface1, n.Iface2, pndp.ParseFilter(n.Filter), n.autosense)
n.instance = o
o.Start()
}
for _, n := range allResponders {
o := pndp.NewResponder(n.Iface, pndp.ParseFilter(n.Filter), n.autosense)
n.instance = o
o.Start()
}
WaitForSignal()
for _, n := range allProxies {
n.instance.Stop()
}
for _, n := range allResponders {
n.instance.Stop()
} }
} }

63
main.go
View File

@ -5,12 +5,12 @@ import (
"os" "os"
"os/signal" "os/signal"
"pndpd/modules" "pndpd/modules"
"pndpd/pndp" _ "pndpd/modules/userInterface"
"syscall" "syscall"
) )
// WaitForSignal Waits (blocking) for the program to be interrupted by the OS // waitForSignal Waits (blocking) for the program to be interrupted by the OS
func WaitForSignal() { func waitForSignal() {
var sigCh = make(chan os.Signal, 1) var sigCh = make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
<-sigCh <-sigCh
@ -18,57 +18,32 @@ func WaitForSignal() {
} }
func main() { func main() {
fmt.Println("PNDPD Version 1.2 - Kioubit 2021") fmt.Println("PNDPD Version 1.2.1 - Kioubit 2021")
if modules.ModuleList != nil {
fmt.Print("Loaded Modules: Core ")
for i := range modules.ModuleList {
fmt.Print((*modules.ModuleList[i]).Name + " ")
}
fmt.Println()
}
if len(os.Args) <= 2 { if len(os.Args) <= 2 {
printUsage() printUsage()
return return
} }
switch os.Args[1] { switch os.Args[1] {
case "respond":
var r *pndp.ResponderObj
if len(os.Args) == 4 {
r = pndp.NewResponder(os.Args[2], pndp.ParseFilter(os.Args[3]), "")
r.Start()
} else {
r = pndp.NewResponder(os.Args[2], nil, "")
r.Start()
}
WaitForSignal()
r.Stop()
case "proxy":
var p *pndp.ProxyObj
if len(os.Args) == 5 {
p = pndp.NewProxy(os.Args[2], os.Args[3], pndp.ParseFilter(os.Args[4]), "")
} else {
p = pndp.NewProxy(os.Args[2], os.Args[3], nil, "")
}
WaitForSignal()
p.Stop()
case "config": case "config":
readConfig(os.Args[2]) readConfig(os.Args[2])
default: default:
for i := range modules.ModuleList { module, command := modules.GetCommand(os.Args[1])
for d := range (*modules.ModuleList[i]).Option { if module != nil {
if (*modules.ModuleList[i]).Option[d].Option == os.Args[1] { modules.ExecuteInit(module, modules.CallbackInfo{
(*modules.ModuleList[i]).Callback(modules.Callback{
CallbackType: modules.CommandLine, CallbackType: modules.CommandLine,
Option: os.Args[1], Command: command,
Arguments: os.Args[1:], Arguments: os.Args[2:],
}) })
return if modules.ExistsBlockingModule() {
} modules.ExecuteComplete()
} waitForSignal()
modules.ShutdownAll()
} }
} else {
printUsage() printUsage()
return }
} }
} }
@ -77,11 +52,9 @@ func printUsage() {
fmt.Println("More options and additional documentation in the example config file") fmt.Println("More options and additional documentation in the example config file")
fmt.Println("Usage:") fmt.Println("Usage:")
fmt.Println("pndpd config <path to file>") fmt.Println("pndpd config <path to file>")
fmt.Println("pndpd respond <interface> <optional whitelist of CIDRs separated by a semicolon>")
fmt.Println("pndpd proxy <interface1> <interface2> <optional whitelist of CIDRs separated by a semicolon applied to interface2>")
for i := range modules.ModuleList { for i := range modules.ModuleList {
for d := range (*modules.ModuleList[i]).Option { for d := range (*modules.ModuleList[i]).Commands {
fmt.Println((*modules.ModuleList[i]).Option[d].Description) fmt.Println("pndpd", (*modules.ModuleList[i]).Commands[d].Description)
} }
} }
} }

View File

@ -7,29 +7,39 @@ import (
// This is an example module that is not imported by the main program // This is an example module that is not imported by the main program
func init() { func init() {
option := []modules.Option{{ commands := []modules.Command{{
Option: "command1", CommandText: "command1",
Description: "This is the usage description for command1", Description: "This is the usage description for command1",
BlockTerminate: true,
}, { }, {
Option: "command2", CommandText: "command2",
Description: "This is the usage description for command2", Description: "This is the usage description for command2",
BlockTerminate: false,
}, },
} }
modules.RegisterModule("Example", option, callback) modules.RegisterModule("Example", commands, initCallback, completeCallback, shutdownCallback)
} }
func callback(callback modules.Callback) { func initCallback(callback modules.CallbackInfo) {
if callback.CallbackType == modules.CommandLine { if callback.CallbackType == modules.CommandLine {
// The command registered by the module has been run in the commandline // The command registered by the module has been run in the commandline
// "arguments" contains the os.Args[] passed to the program after the command registered by this module // "arguments" contains the os.Args[] passed to the program after the command registered by this module
fmt.Println("Command: ", callback.Option) fmt.Println("Command: ", callback.Command.CommandText)
fmt.Println(callback.Arguments) fmt.Println(callback.Arguments)
} else { } else {
// The command registered by the module was found in the config file // The command registered by the module was found in the config file
// "arguments" contains the lines between the curly braces // "arguments" contains the lines between the curly braces
fmt.Println("Command: ", callback.Option) fmt.Println("Command: ", callback.Command.CommandText)
fmt.Println(callback.Arguments) fmt.Println(callback.Arguments)
} }
fmt.Println() fmt.Println()
} }
func completeCallback() {
//Called after the program has passed all options by calls to initCallback()
}
func shutdownCallback() {
fmt.Println("Terminate all work")
}

View File

@ -4,13 +4,16 @@ var ModuleList []*Module
type Module struct { type Module struct {
Name string Name string
Option []Option Commands []Command
Callback func(Callback) InitCallback func(CallbackInfo)
CompleteCallback func()
ShutdownCallback func()
} }
type Option struct { type Command struct {
Option string CommandText string
Description string Description string
BlockTerminate bool
} }
type CallbackType int type CallbackType int
@ -20,16 +23,63 @@ const (
Config CallbackType = 1 Config CallbackType = 1
) )
type Callback struct { type CallbackInfo struct {
CallbackType CallbackType CallbackType CallbackType
Option string Command Command
Arguments []string Arguments []string
} }
func RegisterModule(name string, option []Option, Callback func(Callback)) { func RegisterModule(name string, commands []Command, initCallback func(CallbackInfo), CompleteCallback func(), shutdownCallback func()) {
ModuleList = append(ModuleList, &Module{ ModuleList = append(ModuleList, &Module{
Name: name, Name: name,
Option: option, Commands: commands,
Callback: Callback, InitCallback: initCallback,
CompleteCallback: CompleteCallback,
ShutdownCallback: shutdownCallback,
}) })
} }
func GetCommand(target string) (*Module, Command) {
for i := range ModuleList {
for _, command := range ModuleList[i].Commands {
if command.CommandText == target {
return ModuleList[i], command
}
}
}
return nil, Command{}
}
var runningModules []*Module
func ExecuteInit(module *Module, info CallbackInfo) {
if info.Command.BlockTerminate {
found := false
for _, n := range runningModules {
if n == module {
found = true
break
}
}
if !found {
runningModules = append(runningModules, module)
}
}
module.InitCallback(info)
}
func ExecuteComplete() {
for i := range runningModules {
(*runningModules[i]).CompleteCallback()
}
}
func ShutdownAll() {
for i := range runningModules {
(*runningModules[i]).ShutdownCallback()
}
}
func ExistsBlockingModule() bool {
return len(runningModules) != 0
}

View File

@ -0,0 +1,162 @@
package userInterface
import (
"fmt"
"pndpd/modules"
"pndpd/pndp"
"strings"
)
func init() {
commands := []modules.Command{{
CommandText: "proxy",
Description: "proxy <interface1> <interface2> <optional whitelist of CIDRs separated by a semicolon applied to interface2>",
BlockTerminate: true,
}, {
CommandText: "responder",
Description: "responder <interface> <optional whitelist of CIDRs separated by a semicolon>",
BlockTerminate: true,
}, {
CommandText: "modules",
Description: "modules available - list available modules",
BlockTerminate: false,
}}
modules.RegisterModule("Core", commands, initCallback, completeCallback, shutdownCallback)
}
type configResponder struct {
Iface string
Filter string
autosense string
instance *pndp.ResponderObj
}
type configProxy struct {
Iface1 string
Iface2 string
Filter string
autosense string
instance *pndp.ProxyObj
}
var allResponders []*configResponder
var allProxies []*configProxy
func initCallback(callback modules.CallbackInfo) {
if callback.CallbackType == modules.CommandLine {
switch callback.Command.CommandText {
case "proxy":
if len(callback.Arguments) == 3 {
allProxies = append(allProxies, &configProxy{
Iface1: callback.Arguments[0],
Iface2: callback.Arguments[1],
Filter: callback.Arguments[2],
autosense: "",
instance: nil,
})
} else {
allProxies = append(allProxies, &configProxy{
Iface1: callback.Arguments[0],
Iface2: callback.Arguments[1],
Filter: "",
autosense: "",
instance: nil,
})
}
case "responder":
if len(callback.Arguments) == 2 {
allResponders = append(allResponders, &configResponder{
Iface: callback.Arguments[0],
Filter: callback.Arguments[1],
autosense: "",
instance: nil,
})
} else {
allResponders = append(allResponders, &configResponder{
Iface: callback.Arguments[0],
Filter: "",
autosense: "",
instance: nil,
})
}
case "modules":
if modules.ModuleList != nil {
fmt.Print("Available Modules: ")
for i := range modules.ModuleList {
fmt.Print((*modules.ModuleList[i]).Name + " ")
}
fmt.Println()
}
}
} else {
switch callback.Command.CommandText {
case "proxy":
obj := configProxy{}
filter := ""
for _, n := range callback.Arguments {
if strings.HasPrefix(n, "iface1") {
obj.Iface1 = strings.TrimSpace(strings.TrimPrefix(n, "iface1"))
}
if strings.HasPrefix(n, "iface2") {
obj.Iface2 = strings.TrimSpace(strings.TrimPrefix(n, "iface2"))
}
if strings.HasPrefix(n, "filter") {
filter += strings.TrimSpace(strings.TrimPrefix(n, "filter")) + ";"
if strings.Contains(n, ";") {
panic("Invalid config file syntax")
}
}
if strings.HasPrefix(n, "autosense") {
obj.autosense = strings.TrimSpace(strings.TrimPrefix(n, "autosense"))
}
}
obj.Filter = strings.TrimSuffix(filter, ";")
allProxies = append(allProxies, &obj)
case "responder":
obj := configResponder{}
filter := ""
for _, n := range callback.Arguments {
if strings.HasPrefix(n, "iface") {
obj.Iface = strings.TrimSpace(strings.TrimPrefix(n, "iface"))
}
if strings.HasPrefix(n, "filter") {
filter += strings.TrimSpace(strings.TrimPrefix(n, "filter")) + ";"
if strings.Contains(n, ";") {
panic("Invalid config file syntax")
}
}
if strings.HasPrefix(n, "autosense") {
obj.autosense = strings.TrimSpace(strings.TrimPrefix(n, "autosense"))
}
}
obj.Filter = strings.TrimSuffix(filter, ";")
allResponders = append(allResponders, &obj)
}
}
}
func completeCallback() {
for _, n := range allProxies {
o := pndp.NewProxy(n.Iface1, n.Iface2, pndp.ParseFilter(n.Filter), n.autosense)
n.instance = o
o.Start()
}
for _, n := range allResponders {
o := pndp.NewResponder(n.Iface, pndp.ParseFilter(n.Filter), n.autosense)
n.instance = o
o.Start()
}
}
func shutdownCallback() {
for _, n := range allProxies {
n.instance.Stop()
}
for _, n := range allResponders {
n.instance.Stop()
}
}