Skip to content

Commit

Permalink
Improve configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
Kioubit committed Apr 24, 2023
1 parent b89ed2e commit 7b993d7
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 82 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PNDPD - NDP Responder / Proxy (IPv6)
# PNDPD - NDP Proxy / Responder (IPv6)
## Features
- **Efficiently** process incoming packets using bpf (which runs in the kernel)
- **Proxy** NDP between interfaces with an optional whitelist
Expand Down
90 changes: 59 additions & 31 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,62 +12,90 @@ import (
func readConfig(dest string) {
file, err := os.Open(dest)
if err != nil {
fmt.Println("Error:", err.Error())
os.Exit(1)
configFatalError(err, "")
}
defer func(file *os.File) {
_ = file.Close()
}(file)
var (
currentOption string
blockMap map[string][]string
)

scanner := bufio.NewScanner(file)

for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "//") || strings.TrimSpace(line) == "" {
line, _, _ = strings.Cut(line, "//")
line = strings.TrimSpace(line)
if line == "" {
continue
}
if strings.HasPrefix(line, "debug") {
if strings.Contains(line, "on") {

if after, found := strings.CutPrefix(line, "debug"); found {
if strings.TrimSpace(after) == "on" {
pndp.GlobalDebug = true
fmt.Println("DEBUG ON")
}
continue
}

if strings.HasSuffix(line, "{") {
option := strings.TrimSuffix(strings.TrimSpace(line), "{")
option = strings.TrimSpace(option)
module, command := modules.GetCommand(option, modules.Config)
var lines = make([]string, 0)
if module != nil {
for {
if !scanner.Scan() {
break
}
line := strings.TrimSpace(scanner.Text())
if strings.Contains(line, "}") {
break
}
if option, after, found := strings.Cut(line, "{"); found {
if after != "" {
configFatalError(nil, "Nothing may follow after '{'. A new line must be used")
}
if blockMap != nil {
configFatalError(nil, "A new '{' block was started before the previous one was closed")
}
currentOption = strings.TrimSpace(option)
blockMap = make(map[string][]string)
continue
}

lines = append(lines, line)
}
modules.ExecuteInit(module, modules.CallbackInfo{
CallbackType: modules.Config,
Command: command,
Arguments: lines,
})
if before, after, found := strings.Cut(line, "}"); found {
if after != "" || before != "" {
configFatalError(nil, "Nothing may precede or follow '}'. A new line must be used")
}
if blockMap == nil {
configFatalError(nil, "Found a '}' tag without a matching '{' tag.")
}
module, command := modules.GetCommand(currentOption, modules.Config)
if module == nil {
configFatalError(nil, "Unknown configuration block: "+currentOption)
}
modules.ExecuteInit(module, modules.CallbackInfo{
CallbackType: modules.Config,
Command: command,
Config: blockMap,
})
blockMap = nil
continue
}

if blockMap != nil {
kv := strings.SplitN(line, " ", 2)
if len(kv) != 2 {
configFatalError(nil, "Key without value")
}
if blockMap[kv[0]] == nil {
blockMap[kv[0]] = make([]string, 0)
}
blockMap[kv[0]] = append(blockMap[kv[0]], kv[1])
}
}
_ = file.Close()

if modules.ExistsBlockingModule() {
modules.ExecuteComplete()
waitForSignal()
modules.ShutdownAll()
}

if err := scanner.Err(); err != nil {
panic(err)
configFatalError(err, "")
}
}

func configFatalError(err error, explanation string) {
fmt.Println("Error reading config file:", explanation)
if err != nil {
fmt.Println(err)
}
os.Exit(1)
}
1 change: 1 addition & 0 deletions modules/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type CallbackInfo struct {
CallbackType CallbackType
Command Command
Arguments []string
Config map[string][]string
}

func RegisterModule(name string, commands []Command, initCallback func(CallbackInfo), CompleteCallback func(), shutdownCallback func()) {
Expand Down
83 changes: 37 additions & 46 deletions modules/userInterface/userInterface.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,31 +121,21 @@ func initCallback(callback modules.CallbackInfo) {
switch callback.Command.CommandText {
case "proxy":
obj := configProxy{}
obj.Iface1 = getDefaultConfValue(callback.Config["ext-iface"])
obj.Iface2 = getDefaultConfValue(callback.Config["int-iface"])
obj.autosense = getDefaultConfValue(callback.Config["autosense"])
obj.DontMonitorInterfaces = getDefaultConfValue(callback.Config["monitor-changes"]) == "off"

filter := ""
for _, n := range callback.Arguments {
if strings.HasPrefix(n, "ext-iface") {
obj.Iface1 = strings.TrimSpace(strings.TrimPrefix(n, "ext-iface"))
}
if strings.HasPrefix(n, "int-iface") {
obj.Iface2 = strings.TrimSpace(strings.TrimPrefix(n, "int-iface"))
}
if strings.HasPrefix(n, "filter") {
filter += strings.TrimSpace(strings.TrimPrefix(n, "filter")) + ";"
if strings.Contains(n, ";") {
showError("config: the use of semicolons is not allowed in the filter arguments")
}
}
if strings.HasPrefix(n, "autosense") {
obj.autosense = strings.TrimSpace(strings.TrimPrefix(n, "autosense"))
}
if strings.HasPrefix(n, "monitor-changes") {
obj.DontMonitorInterfaces = strings.TrimSpace(strings.TrimPrefix(n, "monitor-changes")) == "off"
}
if strings.Contains(n, "//") {
showError("config: comments are not allowed after arguments")
for i := range callback.Config["filter"] {
value := callback.Config["filter"][i]
if strings.Contains(value, ";") {
showError("config: the use of semicolons is not allowed in the filter arguments")
}
filter += value + ";"
}
obj.Filter = strings.TrimSuffix(filter, ";")

if obj.autosense != "" && obj.Filter != "" {
showError("config: cannot have both a filter and autosense enabled on a proxy object")
}
Expand All @@ -155,40 +145,40 @@ func initCallback(callback modules.CallbackInfo) {
allProxies = append(allProxies, &obj)
case "responder":
obj := configResponder{}
obj.Iface = getDefaultConfValue(callback.Config["iface"])
obj.autosense = getDefaultConfValue(callback.Config["autosense"])
obj.DontMonitorInterfaces = getDefaultConfValue(callback.Config["monitor-changes"]) == "off"
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, ";") {
showError("config: the use of semicolons is not allowed in the filter arguments")
}
}
if strings.HasPrefix(n, "autosense") {
obj.autosense = strings.TrimSpace(strings.TrimPrefix(n, "autosense"))
}
if obj.autosense != "" && obj.Filter != "" {
showError("config: cannot have both a filter and autosense enabled on a responder object")
}
if obj.Iface == "" {
showError("config: interface not specified in the responder object. (iface parameter)")
}
if strings.HasPrefix(n, "monitor-changes") {
obj.DontMonitorInterfaces = strings.TrimSpace(strings.TrimPrefix(n, "monitor-changes")) == "off"
}
if strings.Contains(n, "//") {
showError("config: comments are not allowed after arguments")
for i := range callback.Config["filter"] {
value := callback.Config["filter"][i]
if strings.Contains(value, ";") {
showError("config: the use of semicolons is not allowed in the filter arguments")
}
filter += value + ";"
}
obj.Filter = strings.TrimSuffix(filter, ";")
allResponders = append(allResponders, &obj)

if obj.autosense != "" && obj.Filter != "" {
showError("config: cannot have both a filter and autosense enabled on a responder object")
}
if obj.Iface == "" {
showError("config: interface not specified in the responder object. (iface parameter)")
}
allResponders = append(allResponders, &obj)
}
}
}

func getDefaultConfValue(in []string) string {
if in == nil {
return ""
}
if len(in) == 0 {
return ""
}
return in[0]
}

func completeCallback() {
for _, n := range allProxies {
o := pndp.NewProxy(n.Iface1, n.Iface2, pndp.ParseFilter(n.Filter), n.autosense, !n.DontMonitorInterfaces)
Expand All @@ -201,6 +191,7 @@ func completeCallback() {
o.Start()
}
}

func shutdownCallback() {
for _, n := range allProxies {
n.instance.Stop()
Expand Down
8 changes: 4 additions & 4 deletions pndpd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

// Proxy example with autoconfigured allow-list
// The allow-list of IP addresses to proxy is configured based
// on the addresses assigned to the interface specified via the autosense parameter.
// on the networks assigned to the interface specified via the autosense parameter.
// This works even if the IP addresses change frequently.
proxy {
ext-iface eth0
int-iface eth1
autosense eth1
autosense eth1 // If eth1 has fd01::1/64 assigned to it, then fd01::/64 will be configured as an allow-list
// Disable monitor-changes only if the IP addresses assigned to the specified interfaces never change (with the exception of the autosense interface)
// monitor-changes on
}
Expand All @@ -28,11 +28,11 @@ proxy {
// Responder example with autoconfigured allow-list (Not recommended - prefer using proxy mode)
// Create an NDP responder that listens and responds on interface "eth0"
// The allow-list of IP addresses to proxy is configured based
// on the addresses assigned to the interface specified via the autosense parameter.
// on the networks assigned to the interface specified via the autosense parameter.
// This works even if the IP addresses change frequently.
responder {
iface eth0
autosense eth0
autosense eth0 // If eth0 has fd01::1/64 assigned to it, then fd01::/64 will be configured as an allow-list
// Disable monitor-changes only if the IP addresses assigned to the specified interfaces never change (with the exception of the autosense interface)
// monitor-changes on
}
Expand Down

0 comments on commit 7b993d7

Please sign in to comment.