Release all ressources on shutdown

This commit is contained in:
Kioubit 2021-12-22 06:04:00 -05:00
parent 24189568b8
commit 338139ad0f
5 changed files with 87 additions and 41 deletions

View File

@ -39,6 +39,7 @@ func readConfig(dest string) {
} }
if strings.HasPrefix(line, "responder") { if strings.HasPrefix(line, "responder") {
obj := configResponder{} obj := configResponder{}
filter := ""
for { for {
scanner.Scan() scanner.Scan()
line = scanner.Text() line = scanner.Text()
@ -46,9 +47,10 @@ func readConfig(dest string) {
obj.Iface = strings.TrimSpace(strings.TrimPrefix(line, "iface")) obj.Iface = strings.TrimSpace(strings.TrimPrefix(line, "iface"))
} }
if strings.HasPrefix(line, "filter") { if strings.HasPrefix(line, "filter") {
obj.Filter = strings.TrimSpace(strings.TrimPrefix(line, "filter")) filter += strings.TrimSpace(strings.TrimPrefix(line, "filter")) + ";"
} }
if strings.HasPrefix(line, "}") { if strings.HasPrefix(line, "}") {
obj.Filter = filter
break break
} }
} }

48
main.go
View File

@ -6,28 +6,34 @@ import (
) )
func main() { func main() {
fmt.Println("PNDPD Version 0.3 by Kioubit") fmt.Println("PNDPD Version 0.4 by Kioubit")
if len(os.Args) <= 2 {
printUsage()
return
}
switch os.Args[1] {
case "respond":
if len(os.Args) == 4 {
go simpleRespond(os.Args[2], parseFilter(os.Args[3]))
} else {
go simpleRespond(os.Args[2], nil)
}
case "proxy":
go proxy(os.Args[2], os.Args[3])
case "readconfig":
readConfig(os.Args[2])
default:
printUsage()
return
}
waitForSignal()
}
func printUsage() {
fmt.Println("Specify command")
fmt.Println("Usage: pndpd readconfig <path to file>") fmt.Println("Usage: pndpd readconfig <path to file>")
fmt.Println("Usage: pndpd respond <interface> <optional whitelist of CIDRs separated with a semicolon>") fmt.Println("Usage: pndpd respond <interface> <optional whitelist of CIDRs separated with a semicolon>")
fmt.Println("Usage: pndpd proxy <interface1> <interface2>") fmt.Println("Usage: pndpd proxy <interface1> <interface2>")
if len(os.Args) <= 1 {
fmt.Println("Specify command")
os.Exit(1)
}
if os.Args[1] == "respond" {
if len(os.Args) == 4 {
simpleRespond(os.Args[2], parseFilter(os.Args[3]))
} else {
simpleRespond(os.Args[2], nil)
}
}
if os.Args[1] == "proxy" {
proxy(os.Args[2], os.Args[3])
}
if os.Args[1] == "readConfig" {
readConfig(os.Args[2])
}
} }

View File

@ -5,28 +5,63 @@ import (
"net" "net"
"os" "os"
"os/signal" "os/signal"
"runtime/pprof"
"strings" "strings"
"sync"
"syscall" "syscall"
"time"
) )
var GlobalDebug = false var GlobalDebug = false
// Items needed for graceful shutdown
var stop = make(chan struct{})
var stopWg sync.WaitGroup
var sigCh = make(chan os.Signal)
func waitForSignal() {
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
<-sigCh
fmt.Println("Shutting down...")
close(stop)
if wgWaitTimout(&stopWg, 10*time.Second) {
fmt.Println("Done")
} else {
fmt.Println("Aborting shutdown, since it is taking too long")
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
}
os.Exit(0)
}
func wgWaitTimout(wg *sync.WaitGroup, timeout time.Duration) bool {
t := make(chan struct{})
go func() {
defer close(t)
wg.Wait()
}()
select {
case <-t:
return true
case <-time.After(timeout):
return false
}
}
func simpleRespond(iface string, filter []*net.IPNet) { func simpleRespond(iface string, filter []*net.IPNet) {
defer stopWg.Done()
stopWg.Add(3) // This function, 2x goroutines
requests := make(chan *NDRequest, 100) requests := make(chan *NDRequest, 100)
defer close(requests) defer close(requests)
go respond(iface, requests, NDP_ADV, filter) go respond(iface, requests, NDP_ADV, filter)
go listen(iface, requests, NDP_SOL) go listen(iface, requests, NDP_SOL)
<-stop
sigCh := make(chan os.Signal)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
select {
case <-sigCh:
fmt.Println("Exit")
os.Exit(0)
}
} }
func proxy(iface1, iface2 string) { func proxy(iface1, iface2 string) {
defer stopWg.Done()
stopWg.Add(9) // This function, 8x goroutines
req_iface1_sol_iface2 := make(chan *NDRequest, 100) req_iface1_sol_iface2 := make(chan *NDRequest, 100)
defer close(req_iface1_sol_iface2) defer close(req_iface1_sol_iface2)
go listen(iface1, req_iface1_sol_iface2, NDP_SOL) go listen(iface1, req_iface1_sol_iface2, NDP_SOL)
@ -46,14 +81,7 @@ func proxy(iface1, iface2 string) {
defer close(req_iface2_adv_iface1) defer close(req_iface2_adv_iface1)
go listen(iface2, req_iface2_adv_iface1, NDP_ADV) go listen(iface2, req_iface2_adv_iface1, NDP_ADV)
go respond(iface1, req_iface2_adv_iface1, NDP_ADV, nil) go respond(iface1, req_iface2_adv_iface1, NDP_ADV, nil)
<-stop
sigCh := make(chan os.Signal)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
select {
case <-sigCh:
fmt.Println("Exit")
os.Exit(0)
}
} }
func parseFilter(f string) []*net.IPNet { func parseFilter(f string) []*net.IPNet {

View File

@ -41,7 +41,6 @@ func htons(v uint16) int {
func htons16(v uint16) uint16 { return v<<8 | v>>8 } func htons16(v uint16) uint16 { return v<<8 | v>>8 }
func listen(iface string, responder chan *NDRequest, requestType NDPType) { func listen(iface string, responder chan *NDRequest, requestType NDPType) {
niface, err := net.InterfaceByName(iface) niface, err := net.InterfaceByName(iface)
if err != nil { if err != nil {
panic(err.Error()) panic(err.Error())
@ -55,7 +54,11 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) {
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
defer syscall.Close(fd) go func() {
<-stop
syscall.Close(fd)
stopWg.Done() // syscall.read does not release when the file descriptor is closed
}()
fmt.Println("Obtained fd ", fd) fmt.Println("Obtained fd ", fd)
if len([]byte(iface)) > syscall.IFNAMSIZ { if len([]byte(iface)) > syscall.IFNAMSIZ {

View File

@ -10,6 +10,7 @@ import (
var globalFd int var globalFd int
func respond(iface string, requests chan *NDRequest, respondType NDPType, filter []*net.IPNet) { func respond(iface string, requests chan *NDRequest, respondType NDPType, filter []*net.IPNet) {
defer stopWg.Done()
fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW) fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
if err != nil { if err != nil {
panic(err) panic(err)
@ -46,7 +47,13 @@ func respond(iface string, requests chan *NDRequest, respondType NDPType, filter
} }
for { for {
n := <-requests var n *NDRequest
select {
case <-stop:
return
case n = <-requests:
}
if filter != nil { if filter != nil {
ok := false ok := false
for _, i := range filter { for _, i := range filter {