반응형

OS: Ubuntu 14.04.1 LTS, Raspbian Jessie

tcpdump: Version 4.6.2 (libpcap 1.6.2)



리눅스에서 네트워크(e.g. 메쉬 네트워크)에 참여하는 각각의 기기가 자신을 거쳐 가는 모든 트래픽 사용량을 네트워크 인터페이스별로 구분해서 통계를 낼 필요가 생겼다.


Tcpdump에서는 "-i any" 옵션을 써서 한꺼번에 모든 인터페이스를 모니터링할 수는 있다. 하지만 아쉽게도 화면에 표시되는 로그 한 줄이 어느 네트워크 인터페이스에 연관된 것인지 알 수 없다. 특히 멀티라디오 멀티채널 라우팅 프로토콜을 돌리는 메쉬 라우터의 입장에서는 지나가는 트래픽 플로우 하나가 어느 네트워크 인터페이스를 거쳐서 지나가고, 소비하는 대역폭의 양이 어느 정도인지 반드시 확인해야 한다.


결국 두 가지 방법 중 하나를 써야 한다.

  1. Tcpdump 인스턴스 하나를 모든 네트워크 인터페이스에 대해서 검사하도록 실행하고, tcpdump에 찍히는 source, destination IP 주소를 검사해서 어느 네트워크 인터페이스에 해당되는지 확인(예측)하는 방법
  2. 각 네트워크 인터페이스별로 tcpdump 인스턴스를 별도로 실행하고, 각 인터페이스별로 구분되는 로그를 활용하기


처음에는 내가 1번 방식을 써서 라우팅 프로토콜에서 tcpdump 로그를 파싱하고 source, destination IP주소를 가지고 네트워크 인터페이스 이름을 알아내는 함수를 코딩해서 썼는데, 예상치 못한 문제가 발생했다. 로그에 찍히는 source와 destination IP 주소가 현재 로깅을 하는 기기와 상관없는 원격지의 IP주소일 경우에는 어느 인터페이스를 통해서 패킷이 들어오고 나가는지 알 수가 없었다. 아주 불가능한 것은 아니지만, 라우팅 테이블에 접근해서 source, destination 양쪽으로 가는 경로와 네트워크 인터페이스를 확인해야 했다. 그리고 외부에서 현재 기기로 들어오는 패킷인지, 패킷이 현재 기기를 통해서 다른 노드(next hop)로 빠져나가는 것인지를 tcpdump 로그에서는 알 길이 없었다. 라우터 입장에서는 똑같은 로그가 두 줄이 찍히는 것처럼 표시가 되었다.


결국 2번 방법을 쓰기로 하고 인터넷을 찾아보니 나와 비슷한 목적으로 tcpdump를 응용하는 사례가 이미 있었다. [1]

핵심은, 동시에 여러 개의 tcpdump 인스턴스를 실행하고, 그 대신 각 인스턴스에서 로그가 한 줄 찍힐 때마다 앞에 네트워크 인터페이스 이름을 추가해서 한 화면에 모두 출력하는 것이고, 이것을 bash script로 만든 것이 첫 번째 답변이다. ([2]에도 있음)


다만 [1]과 [2]에 소개된 스크립트가 라즈베리파이에서는 에러가 나서, 그냥 옵션들 빼고 여러 인터페이스를 동시에 쓰도록 간단하게 만들었다.


[anydump2.sh]

#!/bin/sh


# Get a list of interface names from a user by an argument. (e.g. 'eth0 wlan0')

# Note that the list of interfaces separated by a space should be inside '' or "".

IFLIST=$1


# When this exits, exit all background processes:

trap 'kill $(jobs -p) &> /dev/null && sleep 0.2 &&  echo ' EXIT


# Create one tcpdump output per interface and add the interface name in front of each line:

for interface in $IFLIST

do

        tcpdump -l -i $interface -Nn -b ip -tttt | sed 's/^/'"$interface"' /' 2>/dev/null &

done


# Wait until Ctrl+C

wait



사용 예시:


무선 인터페이스 3개(wlan0, wlan1, wlan2)를 모니터링할 경우,

$ sudo ./anydump2.sh 'wlan0 wlan1 wlan2'



출력 예시:

(listening 이후부터 출력되는 로그의 맨 앞에 인터페이스 이름이 다르게 찍히는 것을 볼 수 있다)


cdsn@cdsn-HP-EliteBook-2740p:~/exp/tcpdm-monitor$ sudo ./anydump2.sh 'wlan0 wlan1 wlan2'

[sudo] password for cdsn: 

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on wlan0, link-type EN10MB (Ethernet), capture size 65535 bytes

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on wlan2, link-type EN10MB (Ethernet), capture size 65535 bytes

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on wlan1, link-type EN10MB (Ethernet), capture size 65535 bytes

wlan0 2016-09-05 17:42:41.671768 IP 192.168.4.6 > 192.168.4.5: ICMP echo request, id 2210, seq 1, length 64

wlan0 2016-09-05 17:42:41.671861 IP 192.168.4.5 > 192.168.4.6: ICMP echo reply, id 2210, seq 1, length 64

wlan0 2016-09-05 17:42:42.650726 IP 192.168.4.6 > 192.168.4.5: ICMP echo request, id 2210, seq 2, length 64

wlan0 2016-09-05 17:42:42.650783 IP 192.168.4.5 > 192.168.4.6: ICMP echo reply, id 2210, seq 2, length 64

wlan0 2016-09-05 17:42:43.650913 IP 192.168.4.6 > 192.168.4.5: ICMP echo request, id 2210, seq 3, length 64

wlan0 2016-09-05 17:42:43.650952 IP 192.168.4.5 > 192.168.4.6: ICMP echo reply, id 2210, seq 3, length 64

wlan1 2016-09-05 17:42:47.740037 IP 192.168.3.6 > 192.168.3.5: ICMP echo request, id 2211, seq 2, length 64

wlan1 2016-09-05 17:42:47.740121 IP 192.168.3.5 > 192.168.3.6: ICMP echo reply, id 2211, seq 2, length 64

wlan1 2016-09-05 17:42:48.752034 IP 192.168.3.6 > 192.168.3.5: ICMP echo request, id 2211, seq 3, length 64

wlan1 2016-09-05 17:42:48.752080 IP 192.168.3.5 > 192.168.3.6: ICMP echo reply, id 2211, seq 3, length 64

wlan1 2016-09-05 17:42:49.747415 IP 192.168.3.6 > 192.168.3.5: ICMP echo request, id 2211, seq 4, length 64

wlan1 2016-09-05 17:42:49.747452 IP 192.168.3.5 > 192.168.3.6: ICMP echo reply, id 2211, seq 4, length 64

^C6 packets captured6 packets captured


6 packets received by filter6 packets received by filter


0 packets dropped by kernel0 packets dropped by kernel


0 packets captured

0 packets received by filter

0 packets dropped by kernel

wlan1 

wlan0 

wlan2 

cdsn@cdsn-HP-EliteBook-2740p:~/exp/tcpdm-monitor$ 





<참고자료>

[1] StackOverflow, "How to display interface in tcpdump output flow?," http://serverfault.com/questions/224698/how-to-display-interface-in-tcpdump-output-flow

[2] Sebastian Haas, "Anydump 1.3," http://sebastianhaas.de/anydump-release/



반응형
블로그 이미지

Bryan_

,
반응형

OS: Raspbian Jessie

HW: Raspberry Pi 2 Model B

NIC: TP-LINK TL-WN722N (Atheros ath9k_htc)



라즈베리파이에 USB 무선랜 카드를 2개를 동시에 꽂아서 쓰면서, 편의를 위해서 각 인터페이스 이름(wlan0, wlan1, ...)에 네트워크 설정을 강제로 지정해 두었다. 예를 들어, wlan0은 hostapd를 돌려서 항상 AP가 되도록 하고, wlan1은 ad-hoc 모드로 다른 라즈베리파이와 네트워크를 구축하도록 하였다.



<문제 상황>


그런데 재부팅하고 나면 거의 매번 인터페이스 이름에 실제로 매핑되는 USB 무선랜카드가 달라지는 현상이 있었다. 인터페이스 이름에 할당되는 무선랜카드의 맥주소(물리적 주소, MAC address, HW address)가 재부팅할 때마다 랜덤하게 배정되는 것이다. 즉, ifconfig로 인터페이스 정보를 볼 때, 아래와 같은 출력 결과에서 HWaddr 영역이 서로 뒤바뀌는 일이 비일비재하게 나타났다.


wlan0     Link encap:Ethernet  HWaddr a0:f3:c1:2b:85:7b  

          inet addr:10.0.4.1  Bcast:10.0.4.255  Mask:255.255.255.0

          inet6 addr: fe80::a2f3:c1ff:fe2b:857b/64 Scope:Link

          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

          RX packets:1301 errors:0 dropped:0 overruns:0 frame:0

          TX packets:1379 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:1000 

          RX bytes:230487 (225.0 KiB)  TX bytes:539231 (526.5 KiB)


wlan1     Link encap:Ethernet  HWaddr a0:f3:c1:2a:ca:04  

          inet addr:192.168.3.4  Bcast:192.168.3.255  Mask:255.255.255.0

          inet6 addr: fe80::a2f3:c1ff:fe2a:ca04/64 Scope:Link

          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

          RX packets:89 errors:0 dropped:0 overruns:0 frame:0

          TX packets:122 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:1000 

          RX bytes:10699 (10.4 KiB)  TX bytes:14048 (13.7 KiB)

(라즈베리파이 기본 설정에서는 NIC가 여러 개일 경우, 

부팅할 때마다 빨간색 표시한 HWaddr 부분이 랜덤으로 계속 바뀐다.)



일반적인 상황에서는 별 문제가 아닐 수도 있겠지만, 내 경우에는 이렇게 맥주소가 뒤바뀌는 현상 때문에 애드혹 네트워크(ad-hoc network)를 구성할 때마다 여간 불편한 일이 아닐 수가 없었다. 애드혹 네트워크 설정을 /etc/network/interfaces 파일에 해 두더라도, 실제로 통신이 가능해지기 위해서는 서로 ping을 주고받는 과정과 어느정도의 시간을 거쳐서 각자 ARP 테이블을 구성해야만 한다.


pi@raspberrypi ~ $ arp -n

Address                  HWtype  HWaddress           Flags Mask            Iface

192.168.3.5              ether   a0:f3:c1:2b:85:e7   CM                    wlan1

192.168.5.1              ether   10:6f:3f:e7:e8:3e   C                     eth0

192.168.3.6              ether   a0:f3:c1:2a:ca:3b   CM                    wlan1

192.168.3.7              ether   00:26:66:4c:1c:1d   CM                    wlan1

(ARP 테이블 예시)


만약 모든 라즈베리파이의 wlan1 인터페이스를 애드혹 네트워크로만 쓰기로 하고, 각 wlan1 인터페이스의 맥 주소와 고정IP 주소를 가지고 수동으로 ARP 테이블에 등록하는 스크립트를 만들어서 부팅 때마다 자동으로 실행되게 한다면, 불편하게 ping을 여러 차례 날릴 필요 없이 애드혹 네트워크를 바로 사용할 수 있게 된다. 하지만 맥주소가 부팅할 때마다 뒤바뀌면 ARP 테이블을 수동으로 추가하더라도 엉뚱한 맥주소가 등록됨으로 인해서 통신을 할 수가 없다.




<해결 방법>


udev에 network rule을 추가하면 된다. [1]

참고로 우분투 데스크탑에는 기본으로 맥주소와 인터페이스 이름을 고정해서 기억하게 되어 있다.

아래와 같은 문법으로 파일을 수정하거나, 없으면 파일을 만들어서 추가한다.


#파일명: /etc/udev/rules.d/10-network.rules


SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="aa:bb:cc:dd:ee:ff", NAME="wlan0"

SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="ff:ee:dd:cc:bb:aa", NAME="wlan1


ATTR{address} 부분에 랜카드의 맥주소, NAME 부분에 강제 지정할 인터페이스 이름을 입력한다.




<참고자료>


[1] https://wiki.archlinux.org/index.php/Network_configuration#Device_names



반응형
블로그 이미지

Bryan_

,