package ports import ( "context" "fmt" "net" "time" "go.uber.org/zap" ) type Server struct { EnabledPortsTCP []string EnabledPortsUDP []string IP string Logger *zap.SugaredLogger store Store } func New(store Store) *Server { return &Server{store: store, Logger: zap.NewNop().Sugar()} } func (s *Server) Start(ctx context.Context) error { for _, port := range s.EnabledPortsTCP { portCtx, cancel := context.WithCancel(ctx) go s.doListenTCP(portCtx, port) defer cancel() } <-ctx.Done() return nil } func (s *Server) AddTCPPort(port string) { s.EnabledPortsTCP = append(s.EnabledPortsTCP, port) } func (s *Server) doListenTCP(ctx context.Context, port string) error { lAddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(s.IP, port)) if err != nil { s.Logger.Warnw("Error resoling listening addr.", "network", "tcp", "port", port) return fmt.Errorf("error resolving listening address: %w", err) } listener, err := net.ListenTCP("tcp", lAddr) if err != nil { return fmt.Errorf("error starting listener: %w", err) } defer listener.Close() go func() { <-ctx.Done() s.Logger.Debug("Listener context cancelled.") listener.Close() }() s.Logger.Infow("Listening for connections to TCP port.", "port", port) for { conn, err := listener.Accept() if err != nil { select { case <-ctx.Done(): s.Logger.Infow("Listener shutting down.", "port", port, "network", "tcp") return nil default: s.Logger.Infow("Error accepting connection.", "error", err) continue } } s.Logger.Infow("Got connection on port.", "port", port, "network", "tcp", "remote_addr", conn.RemoteAddr().String()) conn.SetReadDeadline(time.Now().Add(time.Second * 15)) buf := make([]byte, 256) _, err = conn.Read(buf) if err != nil { buf = []byte{} } attempt := &ConnectionAttempt{ Port: port, Network: "tcp", From: conn.RemoteAddr().String(), Data: buf, } conn.Close() if err := s.store.Add(attempt); err != nil { s.Logger.Warnw("Error storing attempt in store.", "error", err) } } }