github.com/crowdsecurity/crowdsec@v1.6.1/pkg/acquisition/modules/syslog/internal/server/syslogserver.go (about)

     1  package syslogserver
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strings"
     7  	"time"
     8  
     9  	log "github.com/sirupsen/logrus"
    10  	"gopkg.in/tomb.v2"
    11  )
    12  
    13  type SyslogServer struct {
    14  	listenAddr    string
    15  	port          int
    16  	channel       chan SyslogMessage
    17  	udpConn       *net.UDPConn
    18  	Logger        *log.Entry
    19  	MaxMessageLen int
    20  }
    21  
    22  type SyslogMessage struct {
    23  	Message []byte
    24  	Client  string
    25  }
    26  
    27  func (s *SyslogServer) Listen(listenAddr string, port int) error {
    28  
    29  	s.listenAddr = listenAddr
    30  	s.port = port
    31  	udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", s.listenAddr, s.port))
    32  	if err != nil {
    33  		return fmt.Errorf("could not resolve addr %s: %w", s.listenAddr, err)
    34  	}
    35  	udpConn, err := net.ListenUDP("udp", udpAddr)
    36  	if err != nil {
    37  		return fmt.Errorf("could not listen on port %d: %w", s.port, err)
    38  	}
    39  	s.Logger.Debugf("listening on %s:%d", s.listenAddr, s.port)
    40  	s.udpConn = udpConn
    41  
    42  	err = s.udpConn.SetReadDeadline(time.Now().UTC().Add(100 * time.Millisecond))
    43  	if err != nil {
    44  		return fmt.Errorf("could not set read deadline on UDP socket: %w", err)
    45  	}
    46  	return nil
    47  }
    48  
    49  func (s *SyslogServer) SetChannel(c chan SyslogMessage) {
    50  	s.channel = c
    51  }
    52  
    53  func (s *SyslogServer) StartServer() *tomb.Tomb {
    54  	t := tomb.Tomb{}
    55  
    56  	t.Go(func() error {
    57  		for {
    58  			select {
    59  			case <-t.Dying():
    60  				s.Logger.Info("Syslog server tomb is dying")
    61  				err := s.KillServer()
    62  				return err
    63  			default:
    64  				//RFC3164 says 1024 bytes max
    65  				//RFC5424 says 480 bytes minimum, and should support up to 2048 bytes
    66  				b := make([]byte, s.MaxMessageLen)
    67  				n, addr, err := s.udpConn.ReadFrom(b)
    68  				if err != nil && !strings.Contains(err.Error(), "i/o timeout") {
    69  					s.Logger.Errorf("error while reading from socket : %s", err)
    70  					s.udpConn.Close()
    71  					return err
    72  				}
    73  				if err == nil {
    74  					s.channel <- SyslogMessage{Message: b[:n], Client: strings.Split(addr.String(), ":")[0]}
    75  				}
    76  				err = s.udpConn.SetReadDeadline(time.Now().UTC().Add(100 * time.Millisecond))
    77  				if err != nil {
    78  					return err
    79  				}
    80  			}
    81  		}
    82  	})
    83  	return &t
    84  }
    85  
    86  func (s *SyslogServer) KillServer() error {
    87  	err := s.udpConn.Close()
    88  	if err != nil {
    89  		return fmt.Errorf("could not close UDP connection: %w", err)
    90  	}
    91  	close(s.channel)
    92  	return nil
    93  }