From 6de62a1468fef07a74690b878e8d5a451df9f022 Mon Sep 17 00:00:00 2001 From: blotus Date: Tue, 19 Mar 2024 10:22:43 +0100 Subject: [PATCH] warn if user is using inotify to tail a symlink (#2881) --- pkg/acquisition/modules/file/file.go | 61 +++++++++++++++++----------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/pkg/acquisition/modules/file/file.go b/pkg/acquisition/modules/file/file.go index ee3c844a5..c36672507 100644 --- a/pkg/acquisition/modules/file/file.go +++ b/pkg/acquisition/modules/file/file.go @@ -367,9 +367,9 @@ func (f *FileSource) StreamingAcquisition(out chan types.Event, t *tomb.Tomb) er continue } - inotifyPoll := true + pollFile := false if f.config.PollWithoutInotify != nil { - inotifyPoll = *f.config.PollWithoutInotify + pollFile = *f.config.PollWithoutInotify } else { networkFS, fsType, err := types.IsNetworkFS(file) if err != nil { @@ -379,13 +379,23 @@ func (f *FileSource) StreamingAcquisition(out chan types.Event, t *tomb.Tomb) er f.logger.Debugf("fs for %s is network: %t (%s)", file, networkFS, fsType) if networkFS { - f.logger.Warnf("Disabling inotify poll on %s as it is on a network share. You can manually set poll_without_inotify to true to make this message disappear, or to false to enforce inotify poll", file) - - inotifyPoll = false + f.logger.Warnf("Disabling inotify polling on %s as it is on a network share. You can manually set poll_without_inotify to true to make this message disappear, or to false to enforce inotify poll", file) + pollFile = true } } - tail, err := tail.TailFile(file, tail.Config{ReOpen: true, Follow: true, Poll: inotifyPoll, Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekEnd}, Logger: log.NewEntry(log.StandardLogger())}) + filink, err := os.Lstat(file) + + if err != nil { + f.logger.Errorf("Could not lstat() new file %s, ignoring it : %s", file, err) + continue + } + + if filink.Mode()&os.ModeSymlink == os.ModeSymlink && !pollFile { + f.logger.Warnf("File %s is a symlink, but inotify polling is enabled. Crowdsec will not be able to detect rotation. Consider setting poll_without_inotify to true in your configuration", file) + } + + tail, err := tail.TailFile(file, tail.Config{ReOpen: true, Follow: true, Poll: pollFile, Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekEnd}, Logger: log.NewEntry(log.StandardLogger())}) if err != nil { f.logger.Errorf("Could not start tailing file %s : %s", file, err) continue @@ -489,28 +499,33 @@ func (f *FileSource) monitorNewFiles(out chan types.Event, t *tomb.Tomb) error { continue } - inotifyPoll := true + pollFile := false if f.config.PollWithoutInotify != nil { - inotifyPoll = *f.config.PollWithoutInotify + pollFile = *f.config.PollWithoutInotify } else { - if f.config.PollWithoutInotify != nil { - inotifyPoll = *f.config.PollWithoutInotify - } else { - networkFS, fsType, err := types.IsNetworkFS(event.Name) - if err != nil { - f.logger.Warningf("Could not get fs type for %s : %s", event.Name, err) - } - - f.logger.Debugf("fs for %s is network: %t (%s)", event.Name, networkFS, fsType) - - if networkFS { - inotifyPoll = false - } + networkFS, fsType, err := types.IsNetworkFS(event.Name) + if err != nil { + f.logger.Warningf("Could not get fs type for %s : %s", event.Name, err) + } + f.logger.Debugf("fs for %s is network: %t (%s)", event.Name, networkFS, fsType) + if networkFS { + pollFile = true } } - // Slightly different parameters for Location, as we want to read the first lines of the newly created file - tail, err := tail.TailFile(event.Name, tail.Config{ReOpen: true, Follow: true, Poll: inotifyPoll, Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekStart}}) + filink, err := os.Lstat(event.Name) + + if err != nil { + logger.Errorf("Could not lstat() new file %s, ignoring it : %s", event.Name, err) + continue + } + + if filink.Mode()&os.ModeSymlink == os.ModeSymlink && !pollFile { + logger.Warnf("File %s is a symlink, but inotify polling is enabled. Crowdsec will not be able to detect rotation. Consider setting poll_without_inotify to true in your configuration", event.Name) + } + + //Slightly different parameters for Location, as we want to read the first lines of the newly created file + tail, err := tail.TailFile(event.Name, tail.Config{ReOpen: true, Follow: true, Poll: pollFile, Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekStart}}) if err != nil { logger.Errorf("Could not start tailing file %s : %s", event.Name, err) break