레이블이 패킷덤프인 게시물을 표시합니다. 모든 게시물 표시
레이블이 패킷덤프인 게시물을 표시합니다. 모든 게시물 표시

2013년 3월 8일 금요일

DaemonLogger 로 패킷 덤프를 쉽게 해보자

간단한 패킷 로그 데몬인 DaemonLogger 를 소개합니다. 다운로드는 Snort 사이트에서 받을 수 있고 현재 버전은 1.2.1 입니다. (예전에 소개한거 같은데 기억이 안나네요. 아무리 찾아도 쓰여졌던 기록은 없네요 ^^)

http://www.snort.org/snort-downloads/additional-downloads#daemonlogger

libpcap 기반으로 만들어져 있으며 크게 2가지 기능을 가지고 있습니다. 첫번째는 일반적으로 패킷을 스니핑 해서 디스크에 기록을 하며,  1G 가 되면 파일을 새롭게 만듭니다. 두번째는 패킷을 다시 Rewrite 하여 다른 인터페이스로 보내는 기능으로 소프트웨어적인 Tapping 과 같다고 할 수 있습니다.

나온지는 사실 오래되었긴 한데, 패킷 덤프만 필요로 하거나 공부할 목적으로 보신다면 괜챦습니다. 설치는 libpcap 과 libdnet 이 있으면 컴파일에 큰 문제가 없습니다.

# ./configure
# make

기본 도움말은 다음과 같습니다.

# ./daemonlogger -h
USAGE: daemonlogger [-options] <bpf filter>
        -c <count>      Log <count> packets and exit
        -d              Daemonize at startup
        -f <bpf file>   Load BPF filter from <bpf file>
        -F              Flush the pcap buffer for each packet
        -g <group name> Set group ID to <group name>
        -h              Show this usage statement
        -i <intf>       Grab packets from interface <intf>
        -l <path>       Log to directory <path>
        -m <count>      Generate <count> log files and quit
        -M <pct>        In ringbuffer mode log data to <pct> of
                        volume capacity
        -n <name>       Set output filename prefix to <name>
        -o <outf>       Disable logging, retransmit data from
                        <intf> to <outf>
        -p <pidfile>    Use <pidfile> for PID filename
        -P <pidpath>    Use <pidpath> for PID directory
        -r              Activate ringbuffer mode
        -R <pcap file>  Read packets from <pcap file>
        -s <bytes>      Rollover the log file every <bytes>
        -S <snaplen>    Capture <snaplen> bytes per packet
        -t <time>       Rollover the log file on time intervals
        -u <user name>  Set user ID to <user name>
        -v              Show daemonlogger version


아무런 옵션없이 실행하면 바로 패킷 덤프가 시작됩니다.

# ./daemonlogger
[-] Log filename set to "daemonlogger.pcap"
[-] Pidfile configured to "daemonlogger.pid"
[-] Pidpath configured to "/var/run"
[-] Rollover size set to 18446744071562067968 bytes
[-] Rollover time configured for 0 seconds
[-] Pruning behavior set to oldest IN DIRECTORY

-*> DaemonLogger <*-
Version 1.2.1
By Martin Roesch
(C) Copyright 2006-2007 Sourcefire Inc., All rights reserved

sniffing on interface eth0
Logging packets to daemonlogger.pcap.1362698542


따로 경로를 지정하지 않았다면 현 경로에 daemonlogger.pcap.[타임스탬프] 형태로 기록이 됩니다. 몇가지 주요 기능들을 한번 보면 다음과 같습니다.

-c 는 몇개의 패킷을 기록하고 빠져나갈것인지 정의합니다. -d 는 백그라운드로 데몬 형태로 동작합니다. -f 를 통해 BPF 필터가 적용된 파일을 로드할 수 있고 -i 로 패킷 덤프할 인터페이스 그리고 -l 로 기록될 로그 파일 경로를 설정합니다. -s 는 얼마 크기로(바이트 단위) 파일을 롤오버할지 지정하고 -t 는 시간 인터벌로 롤오버를 할 수 있습니다. -n 은 파일이름으로 사용할 것을 지정하는데 기본은 damonlogger.pcap 입니다. -n packetinside 라고 지정하면 packetinside.1362698110 과 같이 생성이 됩니다.

그리고 말씀드렸던 두번째 주요기능으로 다른 인터페이스에 재 전달할 수 있다고 드린 기능은 -o 로 인터페이스를 지정하면 됩니다. 즉 이것은 데이터를 기록하지 않고 바로 지정된 인터페이스로 전달합니다.

# ./daemonlogger -i eth0 -o eth2

간단한 도구라서 쉽게 사용할 수 있으니 참고하세요. 참고로 이와 비슷한 도구들을 블로그에서 많이 소개하였으니 다른 것도 살펴보세요.

즐거운 주말 보내세요 ;-)

[참고]
1. Libdnet
http://libdnet.sourceforge.net/

2012년 11월 16일 금요일

Capstats 로 네트워크 인터페이스 통계 정보 수집하기

Capstats 는 Bro-IDS 에서 배포하는 작은 인터페이스 상태 정보 수집 도구이다. libpcap 을 이용한 것으로 네트워크 인터페이스에서 발생하는 트래픽 정보를 간단히 보여준다. 다운로드는 다음의 경로에서 할 수 있다.

http://www.bro-ids.org/downloads/release/capstats-0.18.tar.gz

컴파일을 하기 위해서는 cmake 가 설치되어 있어야 한다.  우분투 계열이면 apt-get 으로 쉽게 설치 가능하다.

# apt-get install cmake

그리고, 컴파일을 다음과정을 거치면 어려움 없이 쉽게 컴파일이 완료된다.

# ./configure
# make
# make install

사용방법 또한 아주 간단하다. 인터페이스를 지정하고 -I 로 얼마 주기로 정보를 출력할 것인지 시간만 정해주면 된다. -f 를 이용하면 BPF 스타일의 필터를 사용할 수 있고 -n 은 지정한 값 만큼만 출력해주고 중단한다. -w 를 사용하면 패킷을 파일로도 저장할 수 있어, 간단히 패킷 덤프용으로도 사용가능하다.

# capstats -i eth0 -I 1

1352159800.380532 pkts=14 kpps=0.0 kbytes=6 mbps=0.1 nic_pkts=2906 nic_drops=0 u=0 t=14 i=0 o=0 nonip=0
1352159801.380637 pkts=2 kpps=0.0 kbytes=0 mbps=0.0 nic_pkts=2908 nic_drops=0 u=0 t=2 i=0 o=0 nonip=0
1352159802.380823 pkts=10 kpps=0.0 kbytes=0 mbps=0.0 nic_pkts=2918 nic_drops=0 u=2 t=8 i=0 o=0 nonip=0
^C1352159803.374389 pkts=3 kpps=0.0 kbytes=0 mbps=0.0 nic_pkts=2921 nic_drops=0 u=0 t=2 i=0 o=0 nonip=1
1352159803.374402
=== Total

1352159803.374442 pkts=2921 kpps=0.0 kbytes=984 mbps=0.0 nic_pkts=2921 nic_drops=0 u=398 t=2299 i=0 o=14 nonip=210


위 예는 인터페이스 eth0 을 모니터링 하고 -I 로 1초마다 정보를 출력하도록 설정한 것이다. 라인별 각 필드 정보는 다음과 같다:

pkts: Interval 기간에 capstats 가 본 패킷 개수
kpps: 초당 패킷 개수
kbytes: 지정된 Interval 동안 발생한 KBytes
mbps: 초당 Mbits
nic_pkts: libcap 의 pcap_stats() 에 보고된 패킷 개수
nic_drops:libpcap 의  pcap_stats() 에 보고된 Drop 패킷 개수
u: UDP 패킷 개수
t: TCP 패킷 개수
i: ICMP 패킷 개수
nonip: non-IP 패킷 개수


간단하게 네트워크 인터페이스 상황을 모니터링할때 유용하다.

[참고]
1. Capstats 추가 정보

http://www.bro-ids.org/documentation/components/capstats/README.html

2012년 7월 4일 수요일

지속적인 패킷덤프로 인한 메모리 증가

지속적인 패킷 덤프로 인해 메모리 사용률이 크게 증가할 수도 있다. 단순한 패킷 저장이면 모르겠지만, 특정한 경우에는 메모리 사용이 크게 나타났다. 예를들어, tshark 를 통해 특정 필드의 텍스트 값을 저장하는 경우다. 나의 경우가 그런것인지는 모르겠지만, 어느날 프로세스를 확인해 보니 메모리 사용이 9.7 기가나 되었다.

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND          
15175 root      20   0 10.1g 9.7g  28m R    3 30.8 695:36.14 tshark    

TOP 을 통해서 본 것으로 VIRT 는 Virtual Image 로 tshark 에 의해 사용되고 있는 전체 가상 메모리이다.  이건 모든 코드, 데이터 그리고 공유 라이브러리, 메모리 페이지 까지 모두 포함된 것이다. RES 는 Resident Size 로 tshark 에 의해 사용된 스왑되지 않은 물리적인 메모리 양이다. 즉 RES 는 CODE + DATA 라고 할 수 있다.

시스템 활동정보를 살펴보기 위해 SAR 을 이용했고 -r  옵션을 사용하여 메모리 상태 정보를 1초 마다 출력하게 하였다.

# sar -r 1
Linux 2.6.32-5-amd64 () 05/24/2012 _x86_64_ (16 CPU)

05:20:10 PM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit
05:20:11 PM    105292  32898320     99.68    292348  21170036  10814820     24.15
05:20:12 PM    105808  32897804     99.68    292348  21170072  10814820     24.15
05:20:13 PM    105808  32897804     99.68    292348  21170076  10814820     24.15
05:20:14 PM    105684  32897928     99.68    292348  21170112  10814820     24.15

사용되는 메모리 양이 거의 99.68%에 달하고 있다. tshark 프로세스 ID 인 15175 를 Kill 해보도록 하겠다.

# kill 15175
# 18 packets dropped
104133176 packets captured

동작중인 프로세스가 동작을 멈추면서 정보를 남기기를 1억개의 패킷을 캡쳐했다. 프로세스 동작을 중지시키고 다시 살펴본 메모리 사용량은 약 17기가 정도가 되었다. 사용된 메모리는 이제 48.52% 가 되었다.

# sar -r 1
Linux 2.6.32-5-amd64 () 05/24/2012 _x86_64_ (16 CPU)

05:20:46 PM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit
05:20:47 PM   6836172  26167440     79.29    295644  14461968  10814628     24.15
05:20:48 PM   6836432  26167180     79.29    295644  14461968  10814628     24.15
05:20:49 PM  11008288  21995324     66.65    295652  14462016  10027308     22.39
05:20:50 PM  16989180  16014432     48.52    295652  14461988    348920      0.78
05:20:51 PM  16989464  16014148     48.52    295652  14461992    348920      0.78
05:20:52 PM  16989836  16013776     48.52    295652  14461992    348920      0.78
05:20:53 PM  16989852  16013760     48.52    295652  14461996    348920      0.78
05:20:54 PM  16990100  16013512     48.52    295652  14462000    348920      0.78
05:20:55 PM  16990488  16013124     48.52    295652  14462004    348920      0.78
^C

패킷을 장기적으로 덤프하는 경우, 이와 같이 메모리 사용이 커지는 경우가 발생할 수 있으므로 주의깊게 살펴보아야 한다. 모든 경우가 아니지만, 메모리 사용이 많아질 수 있는 패킷 덤프 사용에 다른 프로세스까지 영향을 주어 시스템운영에 문제를 끼칠 수 있다는 점!

2012년 1월 19일 목요일

기가비트 환경에서 패킷덤프 손실을 줄여보기 위한 도구, GULP

기가비트 환경에서 손실없이 패킷을 잡아내기 위한 방법들은 무엇이 있을까? 여러가지 것들이 있을 수 있겠지만, 우리가 흔히 사용하고 있는 리눅스 시스템에서 특별한 변경없이 간단하게 사용할 수 있는 도구 하나를 소개해 볼까 한다. 도구 하나만으로 완벽한 손실없이 패킷을 잡아내기에는 여러가지 환경적 제약이 따른다. 그러므로, 최대한 손실을 줄이면서 패킷을 잡아낼 수 있는 방법을 고민해야 하는데, 스레드 기반의 GULP 가 도움이 되지 않을까 한다.

이 도구를 만든 배경 및 세부적인 정보는 다음 URL 에서 얻을 수 있다.

http://staff.washington.edu/corey/gulp/

비교적 작성된지가 오래되었으므로 이점을 감안하기 바란다.

컴파일은 간단히 make 를 하는 것 만으로도 어렵지 않게 결과를 얻어낼 수 있다.

# make
cc -O    check64bit.c   -o check64bit
./check64bit; rm -f check64bit


If output from Gulp is not compatible with tcpdump or wireshark,
Please see: http://staff.washington.edu/corey/gulp/gulp.html#64bit


cc -g -O gulp.c -o gulp -lpthread -lpcap

실행해 보면 아래와 같은 도움말 정보를 얻을 수 있다.

$ ./gulp
./gulp: Sending raw pcap data to a terminal is not a good idea.
        If you really want to do that, pipe ./gulp through cat but you
        probably want to redirect stdout to a file or another program instead.
        Perhaps you meant to pipe into 'tcpdump -r-' or 'ngrep -I-' ?

Usage: ./gulp [--help | options]
    --help      prints this usage summary
    supported options include:
      -d        decapsulate Cisco ERSPAN GRE packets (sets -f value)
      -f "..."  specify a pcap filter - see manpage and -d
      -i eth#|- specify ethernet capture interface or '-' for stdin
      -s #      specify packet capture "snapshot" length limit
      -r #      specify ring buffer size in megabytes (1-1024)
      -c        just buffer stdin to stdout (works with arbitrary data)
      -x        request exclusive lock (to be the only instance running)
      -X        run even when locking would forbid it
      -v        print program version and exit
      -Vx...x   display packet loss and buffer use - see manpage
      -p #      specify full/empty polling interval in microseconds
      -q        suppress buffer full warnings
      -z #      specify write blocksize (even power of 2, default 65536)
    for long-term capture
      -o dir    redirect pcap output to a collection of files in dir
      -C #      limit each pcap file in -o dir to # times the (-r #) size
      -W #      overwrite pcap files in -o dir rather than start #+1
    and some of academic interest only:
      -B        check if select(2) would ever have blocked on write
      -Y        avoid writes which would block

여러 패킷 덤프 도구들을 사용해 보았다면 옵션만 보아도 어렵지 않게 사용할 수 있다. 참고로 덤프되는 데이터를 바로 터미널에 출력하는 것은 권장 되지 않으므로, 파일로 리다이렉션 하거나 또는 tcpdump, ngrep 과 같은 프로그램으로 리다이렉션 하는 것이 좋다

다음예는 , -i 로 덤프할 인터페이스를 지정하고 '>' 로 파일로 저장하고 있다.

#./gulp -i eth0 > tt

덤프된 파일의 타입을 살펴보면 캡쳐파일임을 알 수 있고 tcpdump 프로그램으로 확인할 수 있다.

# file tt
tt: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 65535)
# tcpdump -r tt
reading from file tt, link-type EN10MB (Ethernet)

다시 패킷을 덤프하는 과정에서 중지하고 살펴보면 12만개 패킷 중 31 개의 패킷이 drop 되었다. 추가로 나오는 정보에서 이런 drop 되는 패킷을 줄이기 위하여 rmem_max 와  rmem_default 값을 늘려주기를 권장하고 있다.

참고로  이전에 작성한 다음 블로그 글을 참고하여 파라미터 값을 조정하면 도움이 될 것이다.

[링크] 커널에서 drop 되는 패킷 수가 많다면...

# ./gulp -i bond0 > tt2
^C
121313 packets captured
121343 packets received by filter
31 packets dropped by kernel

Note ./gulp may drop fewer packets if you increase:
  /proc/sys/net/core/rmem_max and
  /proc/sys/net/core/rmem_default
to 4194304 or more

ring buffer use: 1.8% of 100 MB

느낌상으로는 다른 캡쳐 도구에 비해 손실이 적어 보이기도 한다. 그래서 tcpdump 와 gulp 로 테스트를 해 보았다.

# tcpdump -i bond0 -n -s 1514 -w tt
tcpdump: listening on bond0, link-type EN10MB (Ethernet), capture size 1514 bytes
^C207292 packets captured
208468 packets received by filter
1176 packets dropped by kernel

# ./gulp -i bond0 -s 1514 > tt5
^C
240675 packets captured
240674 packets received by filter
0 packets dropped by kernel
ring buffer use: 0.8% of 100 MB

위 결과를 보면 tcpdump 에서는 1176 개의 패킷이 drop 된 것에 비해 gulp 에서는 한개의 패킷도 drop 되지 않았다.  간단한 결과만 보아도 단순 패킷덤프에서는 gulp 가 tcpdump 보다 우수하다.
gulp 에서 패킷이 유실되는 개수 및 RingBuffer 사용률을 같이 볼 수 있는데 -Vx 를 추가로 주고 덤프를 해 보면 된다.

# ./gulp -i bond0 -Vx > tt3
pkts dropped: 0, ring buf: 0.0%, max: 0.1%
pkts dropped: 0, ring buf: 0.0%, max: 0.1%
pkts dropped: 0, ring buf: 0.1%, max: 0.1%
pkts dropped: 0, ring buf: 0.0%, max: 0.1%
pkts dropped: 0, ring buf: 0.0%, max: 0.1%
pkts dropped: 0, ring buf: 0.0%, max: 0.4%
pkts dropped: 0, ring buf: 0.1%, max: 0.4%
pkts dropped: 0, ring buf: 0.1%, max: 0.4%
pkts dropped: 0, ring buf: 0.0%, max: 0.4%
pkts dropped: 0, ring buf: 0.0%, max: 0.4%
pkts dropped: 0, ring buf: 0.0%, max: 0.4%
pkts dropped: 0, ring buf: 0.1%, max: 0.4%
pkts dropped: 0, ring buf: 0.0%, max: 0.4%
pkts dropped: 0, ring buf: 0.0%, max: 0.4%
pkts dropped: 0, ring buf: 0.0%, max: 0.4%
pkts dropped: 0, ring buf: 0.1%, max: 0.4%
^Cpkts dropped: 0, ring buf: 0.1%, max: 0.4%

27455 packets captured
27454 packets received by filter
0 packets dropped by kernel
ring buffer use: 0.4% of 100 MB

패킷 데이터를 바로 파일로 저장하는 것 외에 프로그램으로 리다이렉션 하여 다음과 같이 사용할 수도 있다.

# ./gulp -i bond0 | tcpdump -r - -w tt4
# ./gulp -i bond0 | ngrep -I - www

그럼 어떤면에서 gulp 가 더 우수한 성능을 보여줄까 ? gulp 를 백그라운드로 실행하고 해당 프로세스를 찾아 strace 로 살펴보았다.

# ./gulp -i bond0 -s 1514 > tt5 &
[2] 5798
# ps -ef | grep gulp
root      5798 18450  0 14:32 pts/1    00:00:00 ./gulp -i bond0 -s 1514
root      6749 18450  0 14:33 pts/1    00:00:00 grep gulp
# strace -p 5798
Process 5798 attached - interrupt to quit
restart_syscall(<... resuming interrupted call ...>) = 0
nanosleep({0, 500000000}, NULL)         = 0
nanosleep({0, 500000000}, NULL)         = 0
nanosleep({0, 500000000}, NULL)         = 0
nanosleep({0, 500000000}, NULL)         = 0
nanosleep({0, 500000000}, NULL)         = 0
nanosleep({0, 500000000}, NULL)         = 0
nanosleep({0, 500000000}, NULL)         = 0
nanosleep({0, 500000000}, NULL)         = 0
nanosleep({0, 500000000}, ^C <unfinished ...>
Process 5798 detached

nanosleep 만이 계속 보인다. 무엇인가 계속 기록하고 해야 할텐데, nanosleep 만 보인다? 혹시 스레드를 사용하는 것일까? 그렇다. 다음과 같이 스레드 카운트를 확인해 보면 3개로 보인다.

# ps -o pid,comm,thcount 5798
  PID COMMAND         THCNT
 5798 gulp                3

이와 달리 같은 형태로  tcpdump 를 살펴보자.

# tcpdump -i bond0 -n -s 1514 -w tt6 &
[2] 9793
# tcpdump: listening on bond0, link-type EN10MB (Ethernet), capture size 1514 bytes

# ps -ef | grep tt6
root      9793 18450  0 14:35 pts/1    00:00:00 tcpdump -i bond0 -n -s 1514 -w tt6
root     10080 18450  0 14:35 pts/1    00:00:00 grep tt6

# strace -p 9793
write(4, "\245\1(\37\315Y\265\206\207\fa\315\257\26\1771u\265\240\223\30309A0\304\362\\\257\7k>~"..., 4096) = 4096
recvfrom(3, "\0\33!R\3334\0PV\250]5\10\0E\0\0(\v\"@\0\200\6Hzo\3\4\22\314\240g"..., 1514, MSG_TRUNC, {sa_family=AF_PACKET, proto=0x800, if10, pkttype=PACKET_HOST, addr(6)={1, 005056a85d35}, [18]) = 60
ioctl(3, SIOCGSTAMP, 0xbfffec18)        = 0
recvfrom(3, "\0PV\250]5\0\33!R\3334\10\0E\0\5\320w+@\0@\6\26\311\314\240g~o\3\4"..., 1514, MSG_TRUNC, {sa_family=AF_PACKET, proto=0x800, if10, pkttype=PACKET_OUTGOING, addr(6)={1, 001b2152db34}, [18]) = 1502
ioctl(3, SIOCGSTAMP, 0xbfffec18)        = 0
recvfrom(3, "\0PV\250]5\0\33!R\3334\10\0E\0\5\320w,@\0@\6\26\310\314\240g~o\3\4"..., 1514, MSG_TRUNC, {sa_family=AF_PACKET, proto=0x800, if10, pkttype=PACKET_OUTGOING, addr(6)={1, 001b2152db34}, [18]) = 1502
ioctl(3, SIOCGSTAMP, 0xbfffec18)        = 0
write(4, "R\370\377\3627\t\2\275\230\22G\321\27414\0172\0\341\224(\4rb\326\275\322\246\333\270\303e\200"..., 4096) = 4096
recvfrom(3, "\0\33!R\3334\0PV\250]5\10\0E\0\0(\v#@\0\200\6Hyo\3\4\22\314\240g"..., 1514, MSG_TRUNC, {sa_family=AF_PACKET, proto=0x800, if10, pkttype=PACKET_HOST, addr(6)={1, 005056a85d35}, [18]) = 60
ioctl(3, SIOCGSTAMP, 0xbfffec18)        = 0
recvfrom(3, ^C <unfinished ...>

무엇인가 아주 바쁘게 기록을 하며 움직이고 있다. 스레드 카운트를 확인 해보면 1 이다.

# ps -o pid,comm,thcount -p 9793
  PID COMMAND         THCNT
 9793 tcpdump             1

즉, GULP 는 스레드로 동작하여 파일 기록시에도 별도의 스레드로 처리하여 더 높은 성능을 나타내고 있는 것이다.

기가비트 네트워크에서는 트래픽 양이 워낙 많기 때문에 운영체제의 네트워크 파라미터를 최적화 하고, 적절한 패킷 캡쳐 도구를 선택해야 한다. 사용환경과 패킷캡쳐의 목적에 따라서 달라지겠지만, 자기에게 맞는 적절한 도구를 테스트해보고 선택하여 사용하면 될 것이다.

2012년 1월 11일 수요일

필요한 내용만 패킷파일로 저장하기

패킷덤프를 하는 과정에서는 통상
1) 네트워크 디바이스 전체를 대상으로 덤프를 하거나
2) 또는 캡처필터를 적용하여 저장하는 것이 일반적이다.

하지만 트래픽이 많은 경우라면 이 또한 여기서 원하는 데이터로 한정하여
필요한 데이터만 저장하기에는 사용자 수고가 따른다.

쉬운 방법으로 이용할 수 있는 것이 ngrep 이 있다. 간단하지만 잘 이용되지 않는것 같아 다시 소개해 본다.

-O 옵션을 이용하면 ngrep 에서 지정한 스트링이 검출된 패킷에 한해서만 PCAP 포맷형태로
저장되므로 필요한 패킷 데이터만을 저장할 수가 있다.

# ngrep -d eth0 -O extracted.pcap GET
or
# tcpdump -i eth0 | ngrep -I - -O extracted.pcap GET

ngrep 을 통해 바로 지정하여 사용하거나 또는 tcpdump 를 통해 입력을 ngrep 에
전달하여 사용할 수도있다.  매칭할 패턴만 잘 정의하고 사용한다면 아주 유용할 것이다.

이전에 ngrep 을 활용한 패킷데이터 추출에 대해 설명한 글이 있으므로 참고하길 바란다.

[링크] Ngrep 을 활용한 패킷 데이터 추출

2010년 8월 18일 수요일

패킷덤프시 프로그램에 따라 캡쳐 사이즈가 달라진다.

패킷 덤프시 가끔 Snaplen 과 관련하여 착각하는 분들이 있어 소개하고자 한다. 일전에도 포스팅된
글에서 잠깐 소개를 하였던 것 같은데, 다시한번 보도록 하자!

패킷덤프를 하였는데, 이상하게 Payload 가 다 포함되어 있지 않고, 어딘가 짤려 있는듯한 패킷파일을
봤다면 패킷 덤프시의 길이가 제대로 정의되어 있는지 확인이 필요하다.

와이어샤크는 기본적으로 덤프 길이가 Length 길이의 최대치인 65535 로 지정되어 있어서, 따로
작게 지정하지 않는 한 이슈가 없다. 그런데 유닉스 환경에서 tcpdump 를 이용하는 경우 미처 깜빡하고
넘어갈 수 있다. 다음의 경우를 보자.

아래버전은 3.9.8 버전이다.
# tcpdump -V
tcpdump version 3.9.8
libpcap version 0.9.8

-c 옵션을 통해 10 개의 패킷만 덤프해 보았는데, capture size 가 96 바이트로 나온다.
# tcpdump -c 10
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

하지만 -s 옵션을 통해 지정하면 해당 크기만큼 덤프가 가능하다.
# tcpdump -c 10 -s 1514
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 1514 bytes

바로 이런 차이로 덤프는 제대로 되었는데, 페이로드가 완벽하게 기록되지 않는 이유가 여기에 있는 것이다.
하지만, tcpdump 최신 버전에서는 변경되었다.

# ./tcpdump -V
tcpdump version 4.1.1
libpcap version 1.1.1

# ./tcpdump -c 10
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes

위와 같이 따로 지정하지도 않았는데, 기본 사이즈가 65535 바이트로 지정되어 있다. 최신 버전을 이용하는
경우 신경 안 써도 되지만, 이전 버전을 사용하는 사용자라면 이점 주의하길 바란다!

2010년 8월 12일 목요일

패킷덤프중 프로세스 강제종료는 일부 데이터손실을 가져올 수 있다.

tcpdump 를 이용하여 패킷을 여러개 기록한 경우가 있다. 이상하게도 이전 포스팅에서 소개한 것과 같이 패킷파일을 열어보려고 하면 'appears to have been cut short in the middle of a packet' 메시지가 나타났지만, 어떤 경우는 아예 데이터가 없거나 일부분만 있는 경우가 나타났다.

일부는 기록이 되었는데, 100% 완벽하게 기록이 되지 못했던 것이다. 이유인즉, kill -9 로 프로세스를 kill 하면서 발생하는 문제였다. tcpdump 옵션을 찾아보니 이를 해결할 옵션이 보인다. 바로 -U 옵션이다.

-U 옵션은 Output 버퍼에 기록되어 기록되기 보다는 바로 디스크에 기록이 된다는 점이다. 데이터를 바로바로 기록할 수 있으므로, 내용 하나하나가 중요한 경우에는 필요한 옵션이다.

       -U     Make  output  saved  via  the  -w  option ``packet-buffered``; i.e., as each packet is
              saved, it will be written to the output file, rather than being written only when  the
              output buffer fills.

              The  -U flag will not be supported if tcpdump was built with an older version of libpcap
              that lacks the pcap_dump_flush() function.

다만, 디스크에 바로 기록하기 때문에 디스크 IO 요청은 늘어난다. 이런점은 고려하여 사용여부를 결정해야 한다.

이 -U 옵션을 좀더 살펴보기 위해 tcpdump 소스코드를 살펴보았다. 일반적인 기록에는 pcap_dump 가 사용되는데 -U 옵션은 pcap_dump_flush 가 사용되고 있다.

    pcap_dump((u_char *)dump_info->p, h, sp);
#ifdef HAVE_PCAP_DUMP_FLUSH
    if (Uflag)
        pcap_dump_flush(dump_info->p);
#endif

    --infodelay;
    if (infoprint)
        info(0);
}

사용되는 libpcap 의 소스코드를 살펴보면 pcap_dump_flush 에는 fflush 로 기록을 하고 있고 , pcap_dump 는 fwrite 를 통해 기록을 하고 있다는 차이점이 있다.


[fflush 이용]

int
pcap_dump_flush(pcap_dumper_t *p)
{

    if (fflush((FILE *)p) == EOF)
        return (-1);
    else
        return (0);
}

[fwrite 이용]

void
pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
{
    register FILE *f;
    struct pcap_sf_pkthdr sf_hdr;

    f = (FILE *)user;
    sf_hdr.ts.tv_sec  = h->ts.tv_sec;
    sf_hdr.ts.tv_usec = h->ts.tv_usec;
    sf_hdr.caplen     = h->caplen;
    sf_hdr.len        = h->len;
    /* XXX we should check the return status */
    (void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
    (void)fwrite(sp, h->caplen, 1, f);
}

그렇기 때문에 kill 로 그냥 프로세스를 종료할 시에는 버퍼 내용이 다 기록된 반면 -9 옵션을 통해 kill 하는 경우 버퍼내용이 기록되지 않으면서 데이터가 완벽하게 기록이 안되는 경우가 발생한 것이다.

패킷 데이터를 덤프하는 경우, 그리고 데이터 내용이 중요한 경우에는 이점을 참고하기 바란다. 정말 패킷이 흘러간 내용이 없는 것으로 판단 착오를 할수도 있기 때문이다. libpcap 을 이용하는 패킷 덤프 프로그램에서는 이런 경우가 있을 수 있으므로 머리속에 기억해 놓자!