LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Networking (http://www.linuxquestions.org/questions/linux-networking-3/)
-   -   Rotating capture files using tcpdump (http://www.linuxquestions.org/questions/linux-networking-3/rotating-capture-files-using-tcpdump-800385/)

prafulnama 04-06-2010 11:43 AM

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

rweaver 04-06-2010 12:55 PM

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.

paulndna 08-13-2010 09:12 PM

try

tcpdump -w capture_%Y-%m-%d-%H:%M:%S

konsolebox 08-14-2010 12:08 AM

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.

gagan_goku 05-12-2011 10:32 PM

use -G <num_seconds> -w 'trace_%Y%m%d-%H%M%S.pcap'

MED07 10-11-2012 10:50 AM

I think this is exactly what Iím looking for but I have a question about functionality.
 
Quote:

Originally Posted by konsolebox (Post 4065827)
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" &

MED07 10-11-2012 11:23 AM

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!

MED07 10-11-2012 03:16 PM

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!

konsolebox 10-11-2012 09:49 PM

Quote:

Originally Posted by MED07 (Post 4803118)
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[@]}" ...


konsolebox 10-12-2012 01:16 AM

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.

MED07 10-12-2012 10:52 AM

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

konsolebox 10-12-2012 07:46 PM

Quote:

Originally Posted by MED07 (Post 4804016)
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


konsolebox 10-12-2012 09:09 PM

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


MED07 10-13-2012 11:23 AM

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!!

konsolebox 10-14-2012 01:49 AM

Welcome :)


All times are GMT -5. The time now is 07:13 PM.