반응형

자바에서 DatagramSocket (UDP 소켓)을 파라미터 없이 생성하거나, 포트 번호만 파라미터로 지정하면 특정 네트워크 인터페이스에 지정되는 것이 아니고, 인터페이스에 상관 없이 포트 번호만 맞으면 패킷을 주고 받는 식으로 작동한다.


실제로 인터넷에 검색해 보면 UDP 소켓을 특정한 네트워크 인터페이스에 지정하고자 하는 요구가 상당히 많은 것을 알 수 있다. 하지만 컴퓨터에 네트워크 인터페이스가 여러 개 있을 경우에 UDP 소켓에서 특정 네트워크 인터페이스를 지정하는 것이 Java Virtual Machine (JVM) 입장에서는 자연스럽지 않을 수 있다. "패킷이 컴퓨터 밖으로 나갈 때, 이를 내보낼 가장 적합한 네트워크 인터페이스를 선택한다"는 보편적인 논리에서 보면 이것은 원래 운영체제(OS)에 내장된 라우팅 프로토콜의 역할이기 때문에, User mode에 있는 JVM 위에서 돌아가는 자바 어플리케이션이 이 역할에 일부분 끼어드는 것처럼 보이는 것이다. 아무튼 자바 어플리케이션 입장에서 불가능하지는 않지만, 바람직한 구성은 아닐 수도 있다.


어쨌든 패킷을 받는 서버 입장에서 DatagramSocket을 생성할 때, 생성자(constructor) 파라미터에 특정 IP 주소와 포트 번호를 모두 파라미터로 넘김으로써 특정 네트워크 인터페이스에서만 패킷을 받도록 지정할 수는 있다.


byte[] receiveData = new byte[1024];

String ip = "192.168.3.4"; // 현재 컴퓨터의 특정 네트워크 인터페이스에 할당된 IP 주소

String port = 54321; // 원하는 포트 번호

DatagramSocket socket = new DatagramSocket(new InetSocketAddress(ip, port));

DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

socket.receive(receivePacket);


패킷을 보내는 클라이언트 입장에서는, 그냥 DatagramPacket을 보낼 때 destination IP 주소를 어떻게 지정하느냐에 따라서 특정 네트워크 인터페이스를 통한 전송 여부가 결정된다. 이것은 운영체제의 라우팅 테이블 설정을 따라간다.


byte[] sendData = new byte[1024];

// sendData에 대한 메세지 생성 작업 수행

String ip = "192.168.3.6";

int port = 54321;

DatagramSocket clientSocket = new DatagramSocket();

DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName(ip), port);

clientSocket.send(sendPacket);


예를 들어, 리눅스의 route 설정이 유선랜 eth0과 무선랜 wlan0 모두 활성화되어 있고, default (0.0.0.0)에 대한 게이트웨이가 유선랜(eth0) 게이트웨이로 설정되어 있다고 가정하자. 이 때, 로컬 네트워크 밖에 있는 인터넷 상의 어떤 기기에 UDP 패킷을 보내고자 한다면, 자바 어플리케이션은 eth0을 통해서 패킷을 보낼 것이다. 이런 경우에 반드시 무선랜 wlan0으로 패킷이 나가도록 하고 싶으면 리눅스에서 route 명령으로 wlan0을 통해서 인터넷으로 나가는 경로를 설정해 주어야 한다.


문제는 서버의 입장에서 DatagramSocket에 특정 IP 주소를 지정해 버리면, 브로드캐스트(broadcast) 메세지를 받지 못하는 문제가 생긴다. 상대편에서 정확하게 IP 주소를 지정해서 보내는 경우에만 패킷을 받을 수 있고, 테스트해 본 결과, 가령 192.168.3.255 와 같은 destination IP로 전송되는 패킷은 받지 못했다.


이 경우에는 서버의 입장에서는 특정한 IP 주소를 지정하지 말고 모든 인터페이스와 모든 주소에 대해서 받을 수 있도록 해 두고, 일단 패킷을 받고 나서 전송자의 IP 주소 대역을 보고 판단하는 루틴을 코드에 추가하는 것이 좋을 것 같다. (이것이 best solution인지는 알 수 없으나, 현재로써는 이것이 working solution이다.)


byte[] receiveData = new byte[1024];

String port = 54321; // 원하는 포트 번호

DatagramSocket socket = new DatagramSocket(port);

DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

socket.receive(receivePacket);




반응형
블로그 이미지

Bryan_

,
반응형

tcpdump를 실행할 때, -i 옵션을 통해서 네트워크 인터페이스를 지정해 주어야 정상적으로 로그를 표시할 수 있다.


동시에 여러 개의 네트워크 인터페이스로부터 정보를 수집하려면, 두 가지 방법이 가능하다.


1. 그냥 tcpdump 프로세스를 각 인터페이스별로 여러 개 실행

screen 같은 도구를 써서 동시에 여러 instance를 실행시킨다. 

예를 들면:

$ sudo screen tcpdump -i eth0

(Ctrl A+D를 눌러 스크린을 빠져나온 뒤,)

$ sudo screen tcpdump -i wlan0


문제는 여러 개의 로그가 별개로 생성되는 것. (같은 로그 파일 이름으로 지정해서 시도하지는 못해서 모르겠다.)



2. tcpdump -i any 옵션으로 실행

이렇게 하면 모든 인터페이스에 대하여 로그가 일괄 수집된다.

문제는 수집할 필요 없는 인터페이스의 로그까지 같이 수집된다.

(머신의 최대 인터페이스 개수가 N일 때, 수집 대상이 1개도 N개도 아닌 경우)


"-i any" 옵션으로 실행할 경우, 각 네트워크 인터페이스에 할당되는 IP 주소의 대역을 의도적으로 다르게 함으로써, 나중에 수집된 로그 파일에서 receiver의 IP 주소 대역을 보고 필터링하는 형태로 원하지 않는 인터페이스에 해당되는 로그를 배제시키는 수밖에 없겠다.

반응형
블로그 이미지

Bryan_

,
반응형

OS: Ubuntu 계열 (11 이상에서 테스트했으나 이하 버전도 아마 가능할 듯)


컴퓨터에 USB 무선랜카드를 여러 개를 번갈아 가면서 쓰다 보면, wlan0, wlan1, wlan2 등 여러 개의 무선 네트워크 인터페이스가 존재하는 것으로 인식될 뿐만 아니라 인터페이스 번호도 뒤죽박죽이 되는 경우가 있다.

또한 네트워크 관련 프로그래밍을 하다 보면 의도적으로 인터페이스 이름을 지정해야 하는 경우도 생기는데, 인터페이스 번호가 달라서 실행하지 못하는 문제가 발생하기도 한다.


이 때는 /etc/udev/rules.d/70-persistent-net.rules 파일을 열어서 인터페이스 번호를 수정할 수 있다.


# This file maintains persistent names for network interfaces.

# See udev(7) for syntax.

#

# Entries are automatically added by the 75-persistent-net-generator.rules

# file; however you are also free to add your own entries.


# PCI device 0x8086:0x10f5 (e1000e)

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:1f:16:08:98:a5", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"


# PCI device 0x8086:0x4236 (iwlagn)

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:16:ea:b1:9d:a4", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="wlan*", NAME="wlan0"


# USB device 0x148f:0x2573 (usb)

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:08:9f:fd:55:4b", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="wlan*", NAME="wlan1"


위에서 빨간색 표시된 영역을 원하는 인터페이스 이름으로 수정할 수 있다. 

만약 현재 쓰지 않는 네트워크 인터페이스일 경우에는 #을 이용해서 주석처리할 수도 있다.

또는 아예 운영체제가 자동으로 네트워크 인터페이스 이름을 처음부터 새로 잡아주길 바란다면 위 파일을 삭제하고 재부팅하는 방법도 있다.




반응형
블로그 이미지

Bryan_

,