두개의 네트워크카드를 이용한 소켓 프로그래밍
글쓴이: yhkim / 작성시간: 목, 2016/02/25 - 6:36오후
Linux-64bit 4.2.0-27-generic #32-Ubuntu SMP Fri Jan 22 04:49:08 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
가상머신에서 리눅스설치하여 소켓 프로그래밍 중에 있습니다.
두개의 네트워크카드를 이용해서 2개의 세션을 하나의 서버에 연결하려고 해서 UDP 또는 TCP 통신을 하여 데이터를 주고 받으려고 합니다.
구글링 결과 setsockopt에 SO_BINDTODEVICE 이용하면 사용하고자 하는 인터페이스카드를 쓸수 있다고해서
사용해 보았지만 와이어샼을 이용해서 패킷을 캡쳐해본 결과 서로 다른 인터페이스를 통해 패킷은 주고 받았지만 어플 레벨에서는 실제 패킷을 받지 못했습니다..
도움을 요청합니다..
memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), DEV_NAME1); ioctl(sockfd, SIOCSIFFLAGS, &ifr); if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) { printf("error\n");
Forums:
Quote:SO_BINDTODEVICEIf a
[1] 매뉴얼에는 이 옵션으로 바인드되면 특정 인터페이스를 통해 들어오는 패킷만 해당 소켓으로 처리하게 된다고 나오는데, 들어오는 패킷 말고 이 소켓을 통해 나가는 패킷도 특정 인터페이스를 통해서만 나가게 되는지는 명시되어 있지 않습니다. 그리고, 설령 나가는 패킷이 SO_BINDTODEVICE에 의해 특정 인터페이스를 통해 나가도록 통제가 가능하다고 가정해도, [2] 상대방으로부터 들어오는 패킷마저 반드시 그 인터페이스로만 도달해 들어오리라는 보장은 없습니다.
간단히 실험해보니, 현재 클라이언트 시스템의 IP주소가 아래와 같이 설정되어 있을 때,
- eth0: 192.168.10.236/24 (MAC: 08:00:27:B6:DF:9E)
- eth1: 192.168.10.249/24 (MAC: 08:00:27:2F:2B:A9)
통신 상대방인 서버의 ARP 엔트리를 조회하면 두 IP 모두에 대해 아래와 같이 eth0의 MAC을 가리키고 있었습니다.
$ arp -a
? (192.168.10.236) at 08:00:27:B6:DF:9E ...
? (192.168.10.249) at 08:00:27:B6:DF:9E ...
아마 두 IP에 대한 ARP 응답이 모두 eth0을 통해서만 이뤄지면서 이런 현상이 생기는 것 같습니다.
이런 상황에서는 상대방의 응답은 항상 eth0으로만 들어올 수밖에 없겠죠.
어쩌면 이런 현상때문에 통신에 문제를 겪고 있는 것인지도 모르겠습니다.
테스트 환경은 아래와 같았습니다.
- 서버 : CentOS 5.11, Linux dev-xt 2.6.18-408.el5 #1 SMP Tue Jan 19 09:14:52 EST 2016 x86_64 x86_64 x86_64 GNU/Linux
- 클라이언트 : Ubuntu 14.04, Linux ubuntu 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
질문을 다시 읽어보니 각각의 인터페이스를 통해 패킷을
질문을 다시 읽어보니 각각의 인터페이스를 통해 패킷을 주고받는 것을 패킷캡처로 확인하셨다고 나와 있네요..
참고로, 문제를 우회하여 SO_BINDTODEVICE 옵션을 쓰지 않는 방법도 있는 것 같아 적어둡니다.
-------
이전 댓글의 [1]과 [2] 문제 즉, [1] 나가는 패킷이 특정 인터페이스를 통해 나가게 만들고 [2] 들어오는 패킷이 특정 인터페이스를 통해 들어오게 만드는 문제를 모두 해결해야 하는데, 아래 페이지가 그 힌트가 될 것 같습니다. [1]은 각 eth0/eth1 각각에 대해 route 테이블을 구성함으로써 해결하는 것 같고, [2]는 ARP filtering을 켜서 해결하는 것 같습니다.
http://askubuntu.com/questions/315166/set-up-two-ip-addresses-with-one-gateway
통신시에는 SO_BINDTODEVICE 옵션은 쓰지 않았고,
아래와 같이 connect() 전에 특정 인터페이스의 로컬IP 주소를 소켓에 bind() 해주면 되네요.
대략 이런 식일텐데 위 코드는 예시를 위해 손으로 대충 작성한 것이고,
제가 테스트한 방법은 netcat을 이용한 것입니다.
서버에서 아래와 같이 실행하고,
클라이언트에는 창을 세 개 띄워서 패킷캡처 명령 두 개와 nc 접속명령을 각각 실행합니다.
아래와 같이 -s 옵션을 주면 클라이언트 쪽에서도 소켓에 특정 로컬 주소를 바인드하게 됩니다.
(192.168.10.10은 서버 주소입니다)
이렇게 해서 서버쪽에서 ARP 엔트리를 조회해보면 아래와 같이 각각 실상황에 맞게 잡혀 있고,
패킷들도 의도한 NIC를 통해 드나드는 것이 tcpdump로 검출되는군요.
$ arp -a
? (192.168.10.236) at 08:00:27:B6:DF:9E ...
? (192.168.10.249) at 08:00:27:2F:2B:A9 ...
댓글 달기