LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Networking
User Name
Password
Linux - Networking This forum is for any issue related to networks or networking.
Routing, network cards, OSI, etc. Anything is fair game.

Notices


Reply
  Search this Thread
Old 04-06-2010, 11:43 AM   #1
prafulnama
LQ Newbie
 
Registered: Mar 2009
Posts: 10

Rep: Reputation: 0
Rotating capture files using tcpdump


Hello,

Ideally, I would like to set up tcpdump to rotate log file every 1 hour and retain files for the lat 14 days but I don't think any combination of -C and -W would allow me to do that (Atleast I haven't been able to figure it out), so I am trying to rotate the files every X number of MB and retain the last 20 files. This seems to be fairly simple with the '-C X -W 20' option but I am having some trouble in customizing the names of the log files. I have tried '-w capture-$(date +%Y-%M-%d-%H:%M-)' thinking that each file would start with the current date and time but all files are using the date and time when the capture was started so the only difference is the number at the end (which is done by -W). I would appreciate any help in figuring out if I can customize the names of the file so that it has the date and time when the capture in started. In fact if I can do that, I dont need the numbers that '-W' appends at the end but I dont know how to get rid of them.

Any if any experts can help me figure out how to do what I originally intended to (Rotate every hour and retain 14 days worth of files), I'll be more than happy :-)

Thanks everyone!
-p
 
Old 04-06-2010, 12:55 PM   #2
rweaver
Senior Member
 
Registered: Dec 2008
Location: Louisville, OH
Distribution: Debian, CentOS, Slackware, RHEL, Gentoo
Posts: 1,833

Rep: Reputation: 167Reputation: 167
Internally in tcpdump I don't believe there is a way to achieve what you want. I'd tend towards writing a script that stopped the running tcpdump and started a new one every hour. Maybe something like this (as a base, needs refined and error checked, tested, etc.)
Code:
#!/bin/bash
killall -9 tcpdump
/usr/sbin/tcpdump -w /var/log/tcpdump/capture_$(date +%Y-%M-%d-%H:%M:%S).log
Then add that to cron to run hourly.
 
Old 08-13-2010, 09:12 PM   #3
paulndna
LQ Newbie
 
Registered: Aug 2010
Posts: 1

Rep: Reputation: 0
try

tcpdump -w capture_%Y-%m-%d-%H:%M:%S
 
Old 08-14-2010, 12:08 AM   #4
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Try this script:
Code:
#!/bin/bash

shopt -s extglob

# variables

CURRENTDATE=''
DDBLOCKSIZE=512
LOGDIR='/var/log/tcpdump'
MAINLOGFILE='main.log'
MAINLOGFILEMAXSIZE=20000000  ## in bytes
OLD=14
QUIT=false
TCPDUMP='/usr/sbin/tcpdump'
TCPDUMPCAPTUREFILEPREFIX='capture-'
TCPDUMPCAPTUREFILESUFFIX=''
TCPDUMPPID=0
TEMPDIR='/var/tmp'

# functions

function log {
	echo "[$(date '+%F %T')] $1" >> "$MAINLOGFILE"
	echo "$1"
}

function checktcpdump {
	[[ $TCPDUMPPID -ne 0 ]] && [[ -e /proc/$TCPDUMPPID ]] && kill -s 0 "$TCPDUMPPID" 2>/dev/null
}

function starttcpdump {
	log "Starting tcpdump..."

	CURRENTDATE=$(date +%F)

	"$TCPDUMP" -w "$LOGDIR/${TCPDUMPCAPTUREFILEPREFIX}${CURRENTDATE}${TCPDUMPCAPTUREFILESUFFIX}.log" &

	if [[ $? -ne 0 ]]; then
		TCPDUMPPID=0
		return 1
	fi

	TCPDUMPPID=$!

	disown "$TCPDUMPPID"

	checktcpdump
}

function starttcpdumploop {
	until starttcpdump; do
		log "Error: Failed to start tcpdump.  Waiting for 20 seconds before next attempt..."
		read -t 20 && QUIT=true
	done
}

function stoptcpdump {
	log "Stopping tcpdump..."
	kill "$TCPDUMPPID"
	checktcpdump && kill -s 9 "$TCPDUMPPID"
	TCPDUMPPID=0
	QUIT=true
}

function restarttcpdump {
	log "Restarting tcpdump..."
	checktcpdump && stoptcpdump
	starttcpdumploop
}

function catchsignals {
	log "Caught a signal..."
	QUIT=true
}

function main {
	local CAPTUREFILEPATTERN FILE MAINLOGFILEMAXBLOCKSIZE NEWDATE SIZE TEMPFILE

	CAPTUREFILEPATTERN="${TCPDUMPCAPTUREFILEPREFIX}[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]${TCPDUMPCAPTUREFILESUFFIX}.log"
	[[ $MAINLOGFILE != */* ]] && MAINLOGFILE=$LOGDIR/$MAINLOGFILE
	(( MAINLOGFILEMAXBLOCKSIZE = (MAINLOGFILEMAXSIZE / DDBLOCKSIZE) + ((MAINLOGFILEMAXSIZE % DDBLOCKSIZE) ? 0 : 1) ))

	log "Starting tcpdump manager script..."

	trap catchsignals SIGQUIT SIGINT SIGKILL SIGTERM

	mkdir -p "$LOGDIR"

	starttcpdumploop

	for (( I = 1;; I = (I + 1) % 20 )); do
		read -t 1 && break  ## we have to separate this from the next statement to ensure proper handling of signals

		[[ $QUIT = true ]] && break

		if [[ I -eq 0 ]]; then
			NEWDATE=$(date +%F)

			if [[ ! $NEWDATE = "$CURRENTDATE" ]]; then
				log "A new day has come."

				if read FILE; then
					log "Deleting $OLD-days old files..."

					while
						log "Deleting $FILE..."

						rm -f "$FILE"

						read FILE
					do
						continue
					done
				fi < <(exec find "$LOGDIR" -name "$CAPTUREFILEPATTERN" -daystart -ctime "+$OLD")   # or -mtime?

				restarttcpdump
			fi
		elif [[ I -eq 1 ]]; then
			SIZE=$(stat --printf=%s "$MAINLOGFILE")

			if [[ $SIZE == +([[:digit:]]) && $(( SIZE / DDBLOCKSIZE )) -gt MAINLOGFILEMAXBLOCKSIZE ]]; then
				echo "Reducing log data in $MAINLOGFILE..."

				TEMPFILE=$TEMPDIR/tcpdump-$RANDOM.tmp

				dd "bs=$DDBLOCKSIZE" "count=$MAINLOGFILEMAXBLOCKSIZE" "if=$MAINLOGFILE" "of=$TEMPFILE"

				cat "$TEMPFILE" > "$MAINLOGFILE"; rm -f "$TEMPFILE"  ## better than mv
			fi
		fi
	done

	checktcpdump && stoptcpdump

	log "Ending tcpdump manager script."
}

# start

main
I thought it was easy from the start but it took long. Please test it in a visible terminal before running in cron.
 
Old 05-12-2011, 10:32 PM   #5
gagan_goku
LQ Newbie
 
Registered: Jan 2010
Posts: 3

Rep: Reputation: 0
use -G <num_seconds> -w 'trace_%Y%m%d-%H%M%S.pcap'
 
Old 10-11-2012, 10:50 AM   #6
MED07
LQ Newbie
 
Registered: Oct 2012
Posts: 5

Rep: Reputation: Disabled
I think this is exactly what I’m looking for but I have a question about functionality.

Quote:
Originally Posted by konsolebox View Post
Try this script:
Code:
#!/bin/bash

shopt -s extglob

# variables

CURRENTDATE=''
DDBLOCKSIZE=512
LOGDIR='/var/log/tcpdump'
MAINLOGFILE='main.log'
MAINLOGFILEMAXSIZE=20000000  ## in bytes
OLD=14
QUIT=false
TCPDUMP='/usr/sbin/tcpdump'
TCPDUMPCAPTUREFILEPREFIX='capture-'
TCPDUMPCAPTUREFILESUFFIX=''
TCPDUMPPID=0
TEMPDIR='/var/tmp'

# functions

function log {
	echo "[$(date '+%F %T')] $1" >> "$MAINLOGFILE"
	echo "$1"
}

function checktcpdump {
	[[ $TCPDUMPPID -ne 0 ]] && [[ -e /proc/$TCPDUMPPID ]] && kill -s 0 "$TCPDUMPPID" 2>/dev/null
}

function starttcpdump {
	log "Starting tcpdump..."

	CURRENTDATE=$(date +%F)

	"$TCPDUMP" -w "$LOGDIR/${TCPDUMPCAPTUREFILEPREFIX}${CURRENTDATE}${TCPDUMPCAPTUREFILESUFFIX}.log" &

	if [[ $? -ne 0 ]]; then
		TCPDUMPPID=0
		return 1
	fi

	TCPDUMPPID=$!

	disown "$TCPDUMPPID"

	checktcpdump
}

function starttcpdumploop {
	until starttcpdump; do
		log "Error: Failed to start tcpdump.  Waiting for 20 seconds before next attempt..."
		read -t 20 && QUIT=true
	done
}

function stoptcpdump {
	log "Stopping tcpdump..."
	kill "$TCPDUMPPID"
	checktcpdump && kill -s 9 "$TCPDUMPPID"
	TCPDUMPPID=0
	QUIT=true
}

function restarttcpdump {
	log "Restarting tcpdump..."
	checktcpdump && stoptcpdump
	starttcpdumploop
}

function catchsignals {
	log "Caught a signal..."
	QUIT=true
}

function main {
	local CAPTUREFILEPATTERN FILE MAINLOGFILEMAXBLOCKSIZE NEWDATE SIZE TEMPFILE

	CAPTUREFILEPATTERN="${TCPDUMPCAPTUREFILEPREFIX}[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]${TCPDUMPCAPTUREFILESUFFIX}.log"
	[[ $MAINLOGFILE != */* ]] && MAINLOGFILE=$LOGDIR/$MAINLOGFILE
	(( MAINLOGFILEMAXBLOCKSIZE = (MAINLOGFILEMAXSIZE / DDBLOCKSIZE) + ((MAINLOGFILEMAXSIZE % DDBLOCKSIZE) ? 0 : 1) ))

	log "Starting tcpdump manager script..."

	trap catchsignals SIGQUIT SIGINT SIGKILL SIGTERM

	mkdir -p "$LOGDIR"

	starttcpdumploop

	for (( I = 1;; I = (I + 1) % 20 )); do
		read -t 1 && break  ## we have to separate this from the next statement to ensure proper handling of signals

		[[ $QUIT = true ]] && break

		if [[ I -eq 0 ]]; then
			NEWDATE=$(date +%F)

			if [[ ! $NEWDATE = "$CURRENTDATE" ]]; then
				log "A new day has come."

				if read FILE; then
					log "Deleting $OLD-days old files..."

					while
						log "Deleting $FILE..."

						rm -f "$FILE"

						read FILE
					do
						continue
					done
				fi < <(exec find "$LOGDIR" -name "$CAPTUREFILEPATTERN" -daystart -ctime "+$OLD")   # or -mtime?

				restarttcpdump
			fi
		elif [[ I -eq 1 ]]; then
			SIZE=$(stat --printf=%s "$MAINLOGFILE")

			if [[ $SIZE == +([[:digit:]]) && $(( SIZE / DDBLOCKSIZE )) -gt MAINLOGFILEMAXBLOCKSIZE ]]; then
				echo "Reducing log data in $MAINLOGFILE..."

				TEMPFILE=$TEMPDIR/tcpdump-$RANDOM.tmp

				dd "bs=$DDBLOCKSIZE" "count=$MAINLOGFILEMAXBLOCKSIZE" "if=$MAINLOGFILE" "of=$TEMPFILE"

				cat "$TEMPFILE" > "$MAINLOGFILE"; rm -f "$TEMPFILE"  ## better than mv
			fi
		fi
	done

	checktcpdump && stoptcpdump

	log "Ending tcpdump manager script."
}

# start

main
I thought it was easy from the start but it took long. Please test it in a visible terminal before running in cron.

It appears this script is a perfect fit for what I need... but I have a question.

Q: Does this rotate the "main.log" file or the tcpdump output?

I am looking for something that will rotate the output of the tcpdump file based on size. So when it reaches a max size the script will start a new tcpdump output with a new name (assuming more than one a day get created)... as in -- if 'x.pcap' exists then add a suffix like a,b,c...

* Also, it appears i'll need to add the specifics of the tcpdump arguments manually within the code
"$TCPDUMP" (manually add arguments here) -w "$LOGDIR/${TCPDUMPCAPTUREFILEPREFIX}${CURRENTDATE}${TCPDUMPCAPTUREFILESUFFIX}.log" &
 
Old 10-11-2012, 11:23 AM   #7
MED07
LQ Newbie
 
Registered: Oct 2012
Posts: 5

Rep: Reputation: Disabled
I added [TCPARGS="-npi eth1 -Xs 1500"] to the variables and inserted $TCPARGS after the TCPDUMP call:

"$TCPDUMP" $TCPARGS -w "$LOGDIR/${TCPDUMPCAPTUREFILEPREFIX}${CURRENTDATE}${TCPDUMPCAPTUREFILESUFFIX}.log" &
and I get..
Starting tcpdump...
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 1500 bytes
so that seems to work as needed

* Any help in rotating the tcpdump output based on size would be great - thanks!
 
Old 10-11-2012, 03:16 PM   #8
MED07
LQ Newbie
 
Registered: Oct 2012
Posts: 5

Rep: Reputation: Disabled
I have gone with a stripped down command/script for now:
tcpdump -npi eth1 -Xs 1500 -C 100 -w /tmp/dump.pcap

and a cron job:
* */1 * * * find /tmp/ -name "*.pcap*" -mmin +59 -exec rm {} \;

The problem of course is that I have to go stop the cron job and kill the pid for the tcpdump - when and if an event happens.

This is just a temporary measure in order to track an inconsistent problem... but if anyone has any better options that will give file rotation, log reporting and can be managed more easily than this one (as I have this running on all 4 of the boxes involved)... please do share - thanks!
 
Old 10-11-2012, 09:49 PM   #9
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
Originally Posted by MED07 View Post
It appears this script is a perfect fit for what I need... but I have a question.

Q: Does this rotate the "main.log" file or the tcpdump output?
The tcpdump output is rotated on a per-day basis while the main.log file is not rotated but truncated to its limit size every time it reaches it. Checking is done every 20 seconds. I think there's still a better way to do it though, like a custom time interval for when the checking would be done. The script would have to be revised for that.
Quote:
I am looking for something that will rotate the output of the tcpdump file based on size. So when it reaches a max size the script will start a new tcpdump output with a new name (assuming more than one a day get created)... as in -- if 'x.pcap' exists then add a suffix like a,b,c...
Well I'll see if we could make things work that way.
Quote:
* Also, it appears i'll need to add the specifics of the tcpdump arguments manually within the code
"$TCPDUMP" (manually add arguments here) -w "$LOGDIR/${TCPDUMPCAPTUREFILEPREFIX}${CURRENTDATE}${TCPDUMPCAPTUREFILESUFFIX}.log" &
Using arrays for passing arguments is the safest way as IFS does not affect it.
Code:
TCPDUMPARGS=("arg with space 1" "arg 2" "...")
tcpdump "${TCPDUMPARGS[@]}" ...
 
Old 10-12-2012, 01:16 AM   #10
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
I updated the script. This time a new filename for the logfile is used every time a new session is started. Note that tcpdump doesn't seem to allow appending of output to a logfile from previous session.

Code:
#!/bin/bash

shopt -s extglob

# variables

CURRENTDATE=''
DDBLOCKSIZE=512
LOGDIR='/var/log/tcpdump'
MAINLOGFILE='main.log'
MAINLOGFILEMAXSIZE=20000000  ## in bytes
OLD=14
QUIT=false
TCPDUMP='/usr/sbin/tcpdump'
TCPDUMPARGS=(-C 1)  ## customize arguments here e.g. (-C 1 "another with spaces")
TCPDUMPCAPTUREFILEPREFIX='capture-'
TCPDUMPCAPTUREFILESUFFIX=''
TCPDUMPPID=0
TEMPDIR='/var/tmp'

# functions

function log {
	echo "[$(date '+%F %T')] $1" >> "$MAINLOGFILE"
	echo "$1"
}

function checktcpdump {
	[[ $TCPDUMPPID -ne 0 ]] && [[ -e /proc/$TCPDUMPPID ]] && kill -s 0 "$TCPDUMPPID" 2>/dev/null
}

function starttcpdump {
	log "Starting tcpdump..."

	CURRENTDATE=$(date +%F)

	BASENAME="${TCPDUMPCAPTUREFILEPREFIX}${CURRENTDATE}${TCPDUMPCAPTUREFILESUFFIX}"

	readarray -t EXISTINGFILES < <(compgen -G "$LOGDIR/${BASENAME}.+([[:digit:]]).log*([[:digit:]])")

	NEXT_SESSION=0

	if [[ ${#EXISTINGFILES[@]} -gt 0 ]]; then
		for FILE in "${EXISTINGFILES[@]}"; do
			SESSION_NUMBER=${FILE%.log*}
			SESSION_NUMBER=${SESSION_NUMBER##*.}
			[[ $SESSION_NUMBER == +([[:digit:]]) && SESSION_NUMBER -ge NEXT_SESSION ]] && NEXT_SESSION=$(( SESSION_NUMBER + 1 ))
		done
	fi

	OUTPUTFILE=$LOGDIR/${BASENAME}.$NEXT_SESSION.log

	"$TCPDUMP" "${TCPDUMPARGS[@]}" -w "$OUTPUTFILE" &

	if [[ $? -ne 0 ]]; then
		TCPDUMPPID=0
		return 1
	fi

	TCPDUMPPID=$!

	disown "$TCPDUMPPID"

	checktcpdump
}

function starttcpdumploop {
	until starttcpdump; do
		log "Error: Failed to start tcpdump.  Waiting for 20 seconds before next attempt..."
		read -t 20
		[[ $QUIT = true ]] && {
			log "Ending tcpdump manager script."
			exit
		}
	done
}

function stoptcpdump {
	log "Stopping tcpdump..."
	kill "$TCPDUMPPID"
	checktcpdump && kill -s 9 "$TCPDUMPPID"
	TCPDUMPPID=0
	QUIT=true
}

function restarttcpdump {
	log "Restarting tcpdump..."
	checktcpdump && stoptcpdump
	starttcpdumploop
}

function catchsignals {
	log "Caught a signal..."
	QUIT=true
}

function main {
	local CAPTUREFILEPATTERN FILE MAINLOGFILEMAXBLOCKSIZE NEWDATE SIZE TEMPFILE

	CAPTUREFILEPATTERN="${TCPDUMPCAPTUREFILEPREFIX}[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]${TCPDUMPCAPTUREFILESUFFIX}.log*"
	[[ $MAINLOGFILE != */* ]] && MAINLOGFILE=$LOGDIR/$MAINLOGFILE
	(( MAINLOGFILEMAXBLOCKSIZE = (MAINLOGFILEMAXSIZE / DDBLOCKSIZE) + ((MAINLOGFILEMAXSIZE % DDBLOCKSIZE) ? 0 : 1) ))

	log "Starting tcpdump manager script..."

	trap catchsignals SIGQUIT SIGINT SIGKILL SIGTERM

	mkdir -p "$LOGDIR"

	starttcpdumploop

	for (( I = 1;; I = (I + 1) % 20 )); do
		read -t 1  ## we have to separate this from the next statement to ensure proper handling of signals

		[[ $QUIT = true ]] && break

		if [[ I -eq 0 ]]; then
			NEWDATE=$(date +%F)

			if [[ ! $NEWDATE = "$CURRENTDATE" ]]; then
				log "A new day has come."

				if read FILE; then
					log "Deleting $OLD-days old files..."

					while
						log "Deleting $FILE..."

						rm -f "$FILE"

						read FILE
					do
						continue
					done
				fi < <(exec find "$LOGDIR" -name "$CAPTUREFILEPATTERN" -daystart -ctime "+$OLD")   # or -mtime?

				restarttcpdump
			fi
		elif [[ I -eq 1 ]]; then
			SIZE=$(stat --printf=%s "$MAINLOGFILE")

			if [[ $SIZE == +([[:digit:]]) && $(( SIZE / DDBLOCKSIZE )) -gt MAINLOGFILEMAXBLOCKSIZE ]]; then
				echo "Reducing log data in $MAINLOGFILE..."

				TEMPFILE=$TEMPDIR/tcpdump-$RANDOM.tmp

				dd "bs=$DDBLOCKSIZE" "count=$MAINLOGFILEMAXBLOCKSIZE" "if=$MAINLOGFILE" "of=$TEMPFILE"

				cat "$TEMPFILE" > "$MAINLOGFILE"; rm -f "$TEMPFILE"  ## better than mv
			fi
		fi
	done

	checktcpdump && stoptcpdump

	log "Ending tcpdump manager script."
}

# start

main
Btw you need bash > 4.0 or else readarray won't work but if you need to use bash 3.0+ just tell me.

For rotation of logfiles based from size you need to use -C of tcpdump. Also, make sure LOGDIR is writeable both by running user and tcpdump (user) - if tcpdump runs with its own user. You can do this by setting 777 to directory, setting 770 with tcpdump, or anything applicable as group, or changing its ownership to tcpdump or tcpdump:tcpdump.

Last edited by konsolebox; 10-12-2012 at 02:37 AM.
 
1 members found this post helpful.
Old 10-12-2012, 10:52 AM   #11
MED07
LQ Newbie
 
Registered: Oct 2012
Posts: 5

Rep: Reputation: Disabled
Thanks Konsolebox -
I have bash version 3.2.25(1)
Will the readarray problem show up when starting/restaring the script? It created today's file with a '.0.log' but when I restart the script it overwrites it.
> Oct 11 11:16 capture-2012-10-11.log
> Oct 12 10:47 capture-2012-10-12.0.log
 
Old 10-12-2012, 07:46 PM   #12
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
Originally Posted by MED07 View Post
Thanks Konsolebox -
I have bash version 3.2.25(1)
Will the readarray problem show up when starting/restaring the script? It created today's file with a '.0.log' but when I restart the script it overwrites it.
> Oct 11 11:16 capture-2012-10-11.log
> Oct 12 10:47 capture-2012-10-12.0.log
The script would overwrite it since readarray doesn't work with bash-3.2.

I have now modified the script. I tested this with bash 3.2 as well. Please try it again.
Code:
#!/bin/bash

shopt -s extglob

# variables

CURRENTDATE=''
DDBLOCKSIZE=512
LOGDIR='/var/log/tcpdump'
MAINLOGFILE='main.log'
MAINLOGFILEMAXSIZE=20000000  ## in bytes
OLD=14
QUIT=false
TCPDUMP='/usr/sbin/tcpdump'
TCPDUMPARGS=(-C 1)  ## customize arguments here e.g. (-C 1 "another with spaces")
TCPDUMPCAPTUREFILEPREFIX='capture-'
TCPDUMPCAPTUREFILESUFFIX=''
TCPDUMPPID=0
TEMPDIR='/var/tmp'

# functions

function log {
	echo "[$(date '+%F %T')] $1" >> "$MAINLOGFILE"
	echo "$1"
}

function checktcpdump {
	[[ $TCPDUMPPID -ne 0 ]] && [[ -e /proc/$TCPDUMPPID ]] && kill -s 0 "$TCPDUMPPID" 2>/dev/null
}

function starttcpdump {
	log "Starting tcpdump..."

	CURRENTDATE=$(date +%F)

	BASENAME="${TCPDUMPCAPTUREFILEPREFIX}${CURRENTDATE}${TCPDUMPCAPTUREFILESUFFIX}"

	{
		if [[ BASH_VERSINFO -ge 4 ]]; then
			readarray -t EXISTINGFILES
		else
			EXISTINGFILES=()
			EXISTINGFILES_COUNT=0
			while read LINE; do
				EXISTINGFILES[EXISTINGFILES_COUNT++]=$LINE
			done
		fi
	} < <(compgen -G "$LOGDIR/${BASENAME}.+([[:digit:]]).log*([[:digit:]])")

	NEXT_SESSION=0

	if [[ ${#EXISTINGFILES[@]} -gt 0 ]]; then
		for FILE in "${EXISTINGFILES[@]}"; do
			SESSION_NUMBER=${FILE%.log*}
			SESSION_NUMBER=${SESSION_NUMBER##*.}
			[[ $SESSION_NUMBER == +([[:digit:]]) && SESSION_NUMBER -ge NEXT_SESSION ]] && NEXT_SESSION=$(( SESSION_NUMBER + 1 ))
		done
	fi

	OUTPUTFILE=$LOGDIR/${BASENAME}.$NEXT_SESSION.log

	"$TCPDUMP" "${TCPDUMPARGS[@]}" -w "$OUTPUTFILE" &

	if [[ $? -ne 0 ]]; then
		TCPDUMPPID=0
		return 1
	fi

	TCPDUMPPID=$!

	disown "$TCPDUMPPID"

	checktcpdump
}

function starttcpdumploop {
	until starttcpdump; do
		log "Error: Failed to start tcpdump.  Waiting for 20 seconds before next attempt..."
		read -t 20
		[[ $QUIT = true ]] && {
			log "Ending tcpdump manager script."
			exit
		}
	done
}

function stoptcpdump {
	log "Stopping tcpdump..."
	kill "$TCPDUMPPID"
	checktcpdump && kill -s 9 "$TCPDUMPPID"
	TCPDUMPPID=0
	QUIT=true
}

function restarttcpdump {
	log "Restarting tcpdump..."
	checktcpdump && stoptcpdump
	starttcpdumploop
}

function catchsignals {
	log "Caught a signal."
	QUIT=true
}

function main {
	local CAPTUREFILEPATTERN FILE NEWDATE SIZE SKIP TEMPFILE

	CAPTUREFILEPATTERN="${TCPDUMPCAPTUREFILEPREFIX}[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]${TCPDUMPCAPTUREFILESUFFIX}.log*"
	[[ $MAINLOGFILE != */* ]] && MAINLOGFILE=$LOGDIR/$MAINLOGFILE

	log "Starting tcpdump manager script..."

	trap catchsignals SIGQUIT SIGINT SIGKILL SIGTERM

	mkdir -p "$LOGDIR"

	starttcpdumploop

	for (( I = 1;; I = (I + 1) % 20 )); do
		read -t 1  ## we have to separate this from the next statement to ensure proper handling of signals

		[[ $QUIT = true ]] && break

		if [[ I -eq 0 ]]; then
			NEWDATE=$(exec date +%F)

			if [[ ! $NEWDATE = "$CURRENTDATE" ]]; then
				log "A new day has come."

				if read FILE; then
					log "Deleting $OLD-days old files..."

					while
						log "Deleting $FILE..."

						rm -f "$FILE"

						read FILE
					do
						continue
					done
				fi < <(exec find "$LOGDIR" -name "$CAPTUREFILEPATTERN" -daystart -ctime "+$OLD")   # or -mtime?

				restarttcpdump
			fi
		elif [[ I -eq 1 ]]; then
			SIZE=$(exec stat --printf=%s "$MAINLOGFILE")

			if [[ $SIZE == +([[:digit:]]) && SIZE -gt MAINLOGFILEMAXSIZE ]]; then
				log "Reducing log data in $MAINLOGFILE..."

				TEMPFILE=$TEMPDIR/tcpdump-$RANDOM.tmp
				SKIP=$(( (SIZE - MAINLOGFILEMAXSIZE) / DDBLOCKSIZE ))

				dd "bs=$DDBLOCKSIZE" "skip=$SKIP" "if=$MAINLOGFILE" "of=$TEMPFILE"
				cat "$TEMPFILE" > "$MAINLOGFILE"; rm -f "$TEMPFILE"  ## better than mv
			fi
		fi
	done

	checktcpdump && stoptcpdump

	log "Ending tcpdump manager script."
}

# start

main

Last edited by konsolebox; 10-12-2012 at 08:58 PM. Reason: Added fixes.
 
Old 10-12-2012, 09:09 PM   #13
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
And this is yet another version for it. This one's more flexible and lighter performance-wise.
Code:
#!/bin/bash

shopt -s extglob

# settings

LOGDIR='/var/log/tcpdump'

MAINLOGFILE='main.log'
MAINLOGFILEMAXSIZE=$(( 20 * 1024 * 1024 ))  ## in bytes. File is reduced when this size is reached.
MAINLOGFILEALLOWANCE=$(( 1 * 1024 * 1024 ))  ## in bytes. This is the extra space given when file is reduced.
MAINLOGCHECKINTERVALS=300 ## seconds. Recommended: >= 300

TCPDUMP='/usr/sbin/tcpdump'
TCPDUMPARGS=(-C 1) ## customize arguments here e.g. (-C 1 "another with spaces")
TCPDUMPCAPTUREFILEPREFIX='capture-'
TCPDUMPCAPTUREFILESUFFIX=''
TCPDUMPCHECKINTERVALS=60 ## seconds

OLD=14  ## days

DDBLOCKSIZE=512  ## bytes

TEMPDIR='/var/tmp'

# other variables

CURRENTDATE=''
QUIT=false
TCPDUMPPID=0

# functions

function log {
	echo "[$(date '+%F %T')] $1" >> "$MAINLOGFILE"
	echo "$1"
}

function checktcpdump {
	[[ $TCPDUMPPID -ne 0 ]] && [[ -e /proc/$TCPDUMPPID ]] && kill -s 0 "$TCPDUMPPID" 2>/dev/null
}

function starttcpdump {
	log "Starting tcpdump..."

	local CURRENTDATE=CURRENTDATE=$(date +%F)
	local BASENAME="${TCPDUMPCAPTUREFILEPREFIX}${CURRENTDATE}${TCPDUMPCAPTUREFILESUFFIX}"
	local -a EXISTINGFILES
	
	{
		if [[ BASH_VERSINFO -ge 4 ]]; then
			readarray -t EXISTINGFILES
		else
			EXISTINGFILES=()
			local -i I=0
			while read LINE; do
				EXISTINGFILES[I++]=$LINE
			done
		fi
	} < <(compgen -G "$LOGDIR/${BASENAME}.+([[:digit:]]).log*([[:digit:]])")

	local NEXT_SESSION=0

	if [[ ${#EXISTINGFILES[@]} -gt 0 ]]; then
		local SESSION_NUMBER
		for FILE in "${EXISTINGFILES[@]}"; do
			SESSION_NUMBER=${FILE%.log*}
			SESSION_NUMBER=${SESSION_NUMBER##*.}
			[[ $SESSION_NUMBER == +([[:digit:]]) && SESSION_NUMBER -ge NEXT_SESSION ]] && NEXT_SESSION=$(( SESSION_NUMBER + 1 ))
		done
	fi

	local OUTPUTFILE=$LOGDIR/${BASENAME}.$NEXT_SESSION.log

	"$TCPDUMP" "${TCPDUMPARGS[@]}" -w "$OUTPUTFILE" &

	if [[ $? -ne 0 ]]; then
		TCPDUMPPID=0
		return 1
	fi

	TCPDUMPPID=$!

	disown "$TCPDUMPPID"

	checktcpdump
}

function starttcpdumploop {
	until starttcpdump; do
		log "Error: Failed to start tcpdump.  Waiting for 20 seconds before next attempt..."
		read -t 20
		[[ $QUIT = true ]] && {
			log "Ending tcpdump manager script."
			exit
		}
	done
}

function stoptcpdump {
	log "Stopping tcpdump..."
	kill "$TCPDUMPPID"
	checktcpdump && kill -s 9 "$TCPDUMPPID"
	TCPDUMPPID=0
	QUIT=true
}

function restarttcpdump {
	log "Restarting tcpdump..."
	checktcpdump && stoptcpdump
	starttcpdumploop
}

function catchsignals {
	log "Caught a signal."
	QUIT=true
}

function main {
	local CAPTUREFILEPATTERN FILE NEWDATE SIZE TEMPFILE
	local -i I

	CAPTUREFILEPATTERN="${TCPDUMPCAPTUREFILEPREFIX}[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]${TCPDUMPCAPTUREFILESUFFIX}.log*"
	[[ $MAINLOGFILE != */* ]] && MAINLOGFILE=$LOGDIR/$MAINLOGFILE

	log "Starting tcpdump manager script..."

	[[ $MAINLOGFILEMAXSIZE == +([[:digit:]]) && MAINLOGFILEMAXSIZE -gt DDBLOCKSIZE ]] || {
		echo "MAINLOGFILEMAXSIZE is not valid."
		return 1
	}
	[[ $MAINLOGFILEALLOWANCE == +([[:digit:]]) && MAINLOGFILEALLOWANCE -gt DDBLOCKSIZE && MAINLOGFILEALLOWANCE -lt MAINLOGFILEMAXSIZE ]] || {
		echo "MAINLOGFILEALLOWANCE is not valid."
		return 1
	}

	trap catchsignals SIGQUIT SIGINT SIGKILL SIGTERM

	mkdir -p "$LOGDIR"

	starttcpdumploop

	for (( I = 1;; I = (I + 1) % 10000 )); do
		read -t 1  ## we have to separate this from the next statement to ensure proper handling of signals

		[[ $QUIT = true ]] && break

		if (( (I % TCPDUMPCHECKINTERVALS) == 0 )); then
			NEWDATE=$(exec date +%F)

			if [[ ! $NEWDATE = "$CURRENTDATE" ]]; then
				log "A new day has come."

				if read FILE; then
					log "Deleting $OLD-days old files..."

					while
						log "Deleting $FILE..."

						rm -f "$FILE"

						read FILE
					do
						continue
					done
				fi < <(exec find "$LOGDIR" -name "$CAPTUREFILEPATTERN" -daystart -ctime "+$OLD")   # or -mtime?

				restarttcpdump
			fi
		fi
		if (( (I % MAINLOGCHECKINTERVALS) == 0 )); then
			SIZE=$(exec stat --printf=%s "$MAINLOGFILE")

			if [[ $SIZE == +([[:digit:]]) && SIZE -gt MAINLOGFILEMAXSIZE ]]; then
				log "Reducing log data in $MAINLOGFILE..."

				TEMPFILE=$TEMPDIR/tcpdump-$RANDOM.tmp
				SKIP=$(( (SIZE - (MAINLOGFILEMAXSIZE - MAINLOGFILEALLOWANCE)) / DDBLOCKSIZE ))

				dd "bs=$DDBLOCKSIZE" "skip=$SKIP" "if=$MAINLOGFILE" "of=$TEMPFILE"
				cat "$TEMPFILE" > "$MAINLOGFILE"; rm -f "$TEMPFILE"  ## better than mv
			fi
		fi
	done

	checktcpdump && stoptcpdump

	log "Ending tcpdump manager script."
}

# start

main

Last edited by konsolebox; 10-12-2012 at 09:12 PM.
 
1 members found this post helpful.
Old 10-13-2012, 11:23 AM   #14
MED07
LQ Newbie
 
Registered: Oct 2012
Posts: 5

Rep: Reputation: Disabled
you're awesome! - that did it:
- capture-2012-10-13.0.log (capture started)
- capture-2012-10-13.0.log1 (capture rolled over based on file size)
- capture-2012-10-13.1.log (capture stopped and restarted)
- capture-2012-10-13.2.log (capture stopped and restarted)
- main.log

I think I'll use a cron job to start this script '@reboot' if that works... and will continue to use a cron job to clean off logs older than x number of hours.

Thanks so much for your help!!
 
Old 10-14-2012, 01:49 AM   #15
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Welcome
 
  


Reply

Tags
log, name, rotate, tcpdump



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Help with tcpdump to capture traffic. abefroman Linux - Networking 4 04-04-2008 03:08 AM
tcpdump does not capture all packets logicalfuzz Linux - Networking 1 03-19-2007 12:47 PM
Using Tcpdump and Tethereal to capture packets shanu_technical Linux - Networking 3 06-14-2006 08:54 AM
not capture payload with tcpdump? hedpe Linux - Networking 6 02-07-2006 02:23 PM
retransmiting tcpdump capture file? JWT2 Linux - Networking 9 10-09-2005 08:27 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Networking

All times are GMT -5. The time now is 03:35 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration