두개의 네트워크카드를 이용한 소켓 프로그래밍

yhkim의 이미지

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");

chanik의 이미지

Quote:
SO_BINDTODEVICE
If a socket is bound to an interface, only packets received from that particular interface are processed by the socket

[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

chanik의 이미지

질문을 다시 읽어보니 각각의 인터페이스를 통해 패킷을 주고받는 것을 패킷캡처로 확인하셨다고 나와 있네요..

참고로, 문제를 우회하여 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() 해주면 되네요.

int sock = socket( PF_INET, SOCK_STREAM, 0); 
 
struct sockaddr_in local_addr;
local_addr.sin_family = AF_INET;
local_addr.sin_port = 0;                                   // random port
local_addr.sin_addr.s_addr= inet_addr( "192.168.10.249");  // 특정인터페이스의 로컬 IP
bind( sock, (struct sockaddr*)&local_addr, sizeof(local_addr) );
 
connect(sock, ...);

대략 이런 식일텐데 위 코드는 예시를 위해 손으로 대충 작성한 것이고,
제가 테스트한 방법은 netcat을 이용한 것입니다.

서버에서 아래와 같이 실행하고,

$ for ((i=0; i<100; i++)); do echo "OK" | nc -l 12345; done

클라이언트에는 창을 세 개 띄워서 패킷캡처 명령 두 개와 nc 접속명령을 각각 실행합니다.

$ sudo tcpdump -i eth0 'tcp port 12345'

$ sudo tcpdump -i eth1 'tcp port 12345'

아래와 같이 -s 옵션을 주면 클라이언트 쪽에서도 소켓에 특정 로컬 주소를 바인드하게 됩니다.
(192.168.10.10은 서버 주소입니다)

$ nc -s 192.168.10.236 192.168.10.10 12345
OK
$ nc -s 192.168.10.249 192.168.10.10 12345
OK

이렇게 해서 서버쪽에서 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 ...

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.