From edb17e515dcbf12e8891e484bd7a5c515ad1784e Mon Sep 17 00:00:00 2001 From: Julian Wecke Date: Wed, 10 Jul 2024 21:17:25 +0200 Subject: [PATCH] Lineproto code refactor Big refactor of line protocol code. Now with simple reload for lookuptables. --- cmd/icalm-server/main.go | 33 ++++++-- internal/lineproto/lineproto.go | 128 ++++++++++++++++++++++++++------ 2 files changed, 135 insertions(+), 26 deletions(-) diff --git a/cmd/icalm-server/main.go b/cmd/icalm-server/main.go index a1355a5..0574203 100644 --- a/cmd/icalm-server/main.go +++ b/cmd/icalm-server/main.go @@ -44,6 +44,7 @@ func main() { os.Exit(1) } + servers := make([]*lineproto.LineServer,0) toclose := make([]io.Closer, 0) lookuptable, err := config.LoadLookupTableFromFile(*cidrfileFlag) @@ -61,8 +62,9 @@ func main() { if err != nil { log.Fatal(err) } - log.Printf("Listening on %v for lineproto requests \n", lineserver.Addr()) - toclose = append(toclose, lineserver) + log.Printf("Listening on %v for lineproto requests \n", lineserver.Listener.Addr()) + toclose = append(toclose, lineserver.Listener) + servers = append(servers, lineserver) } if *lineunixFlag != "" { @@ -70,13 +72,34 @@ func main() { if err != nil { log.Fatal(err) } - log.Printf("Serving lineproto @ %v \n", lineunixserver.Addr()) - toclose = append(toclose, lineunixserver) + log.Printf("Serving lineproto @ %v \n", lineunixserver.Listener.Addr()) + toclose = append(toclose, lineunixserver.Listener) + servers = append(servers, lineunixserver) } sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) - <-sigChan + + sigHupChan := make(chan os.Signal, 1) + signal.Notify(sigHupChan, syscall.SIGHUP) + + + run := true + for run { + select { + case <-sigChan: + run = false + case <-sigHupChan: + for _, serv := range servers { + lookuptable, err := config.LoadLookupTableFromFile(*cidrfileFlag) + if err != nil { + log.Fatal(err) + } + serv.Reload(lookuptable) + log.Printf("Reloaded lookuptable (%v entries)\n", lookuptable.Size()) + } + } + } log.Println("Shutting down") diff --git a/internal/lineproto/lineproto.go b/internal/lineproto/lineproto.go index 3f9a6e5..55d9db9 100644 --- a/internal/lineproto/lineproto.go +++ b/internal/lineproto/lineproto.go @@ -5,44 +5,130 @@ import ( "github.com/securitym0nkey/icalm/pkg/iplookup" "io" "net" + "log" + "sync" ) -func ServLineProto(r io.Reader, w io.Writer, table iplookup.LookupTable) { - scanner := bufio.NewScanner(r) + +type LineServerConnection struct { + conn net.Conn + update_chan chan *iplookup.LookupTable +} + +type LineServer struct { + Listener net.Listener + clients map[net.Conn]*LineServerConnection + table iplookup.LookupTable + clientsMutex sync.Mutex +} + + + +func ServLineProto(r io.Reader, w io.Writer, inittable *iplookup.LookupTable, newtable_chan chan *iplookup.LookupTable) { + + quit_chan := make(chan int) + defer close(quit_chan) + + request_chan := make(chan string) + defer close(request_chan) + + wr := bufio.NewWriter(w) + table := *(inittable) - for scanner.Scan() { - i := scanner.Text() - ip := net.ParseIP(i) - if ip != nil { - s, o := table.Lookup(ip) - if o { - wr.WriteString(s) - } + + // wait for new request (lines) in separate goroutine + go func(){ + scanner := bufio.NewScanner(r) + for scanner.Scan() { + r := scanner.Text() + request_chan <- r + } + quit_chan <- 0 + }() + + + // main loop per client + for { + select { + case request := <- request_chan: + ip := net.ParseIP(request) + s, o := table.Lookup(ip) + if o { + wr.WriteString(s) + } + wr.WriteString("\n") + wr.Flush() + case newtable := <- newtable_chan: + table = *(newtable) + case <-quit_chan: + return } - wr.WriteString("\n") - wr.Flush() } } -func NewLineServer(network string, addr string, table iplookup.LookupTable) (net.Listener, error) { - server, err := net.Listen(network, addr) +func (s *LineServer) AddClientConnection(c *LineServerConnection) { + s.clientsMutex.Lock() + defer s.clientsMutex.Unlock() + log.Printf("Client %s connected", c.conn.RemoteAddr()) + s.clients[c.conn] = c +} + + +func (s *LineServer) RemoveClientConnection(c *LineServerConnection) { + s.clientsMutex.Lock() + defer s.clientsMutex.Unlock() + log.Printf("Client %s disconnected", c.conn.RemoteAddr()) + delete(s.clients, c.conn) +} + +func (s *LineServer) Reload(newtable iplookup.LookupTable){ + s.clientsMutex.Lock() + defer s.clientsMutex.Unlock() + + s.table = newtable + for _, client := range s.clients { + client.update_chan <- &(newtable) + } + +} + +func NewLineServer(network string, addr string, table iplookup.LookupTable) (*LineServer, error) { + listener, err := net.Listen(network, addr) + if err != nil { return nil, err } - go func(s net.Listener) { - defer s.Close() + + server := &LineServer { + Listener: listener, + clients: make(map[net.Conn]*LineServerConnection), + table: table, + } + + go func(s *LineServer) { + defer s.Listener.Close() for { - conn, err := s.Accept() + conn, err := s.Listener.Accept() if err != nil { break } - go func(c net.Conn) { - defer c.Close() - ServLineProto(c, c, table) - }(conn) + + client := &LineServerConnection{ + conn: conn, + update_chan: make(chan *iplookup.LookupTable), + } + server.AddClientConnection(client) + + go func(c *LineServerConnection) { + defer c.conn.Close() + defer server.RemoveClientConnection(c) + ServLineProto(c.conn, c.conn, &server.table, c.update_chan) + + }(client) } }(server) + return server, nil }