Linux를 사용하여 전송되는 이더넷 인터페이스 데이터를 지정하는 방법
-
05-07-2019 - |
문제
동일한 서브넷에 두 개의 네트워크 인터페이스가있는 Linux 기반 서버 시스템에서 작업 중입니다 (지금은 172.17.32.10
& 172.17.32.11
). 네트워크의 호스트에 데이터를 보내면 데이터가 전송되는 서버의 인터페이스를 지정하고 싶습니다. 소프트웨어에서 한 인터페이스에서 다른 인터페이스에서 다른 인터페이스 (또는 둘 다를 전송할 수도 있음)로 전환 할 수 있어야합니다 (이 응용 프로그램에는 정적 라우팅 규칙이 작동하지 않습니다).
StackoverFlow에서 NetLink 라이브러리를 사용하여 즉시 경로를 수정하는 관련 질문을 찾았습니다. 이것은 직관적으로 작동하는 것처럼 보이지만 동일한 결과를 달성 할 다른 옵션이 있는지 궁금합니다.
해결책
범죄는 의도하지 않았지만 bind ()를 사용하는 것에 대한 답은 잘못되었습니다. Bind ()는 패킷 IP 헤더 내에있는 소스 IP 주소를 제어합니다. 패킷을 보내는 데 사용되는 인터페이스를 제어하지 않습니다. 커널의 라우팅 테이블을 참조하여 특정 대상에 도달하는 데 가장 적은 비용이있는 인터페이스를 결정합니다. (*참고 참조)
대신, 당신은 an을 사용해야합니다 SO_BINDTODEVICE
양말. 이것은 두 가지를 수행합니다.
- 패킷은 커널 라우팅 테이블의 말에 관계없이 지정한 인터페이스에서 항상 방출됩니다.
- 지정된 인터페이스에 도착하는 패킷 만 소켓에 건네집니다. 다른 인터페이스에 도착하는 패킷은 그렇지 않습니다.
사이에 전환하려는 여러 인터페이스가있는 경우 인터페이스 당 하나의 소켓을 작성하는 것이 좋습니다. 또한 묶인 인터페이스에 패킷 만 받기 때문에 이러한 소켓을 모두 추가해야합니다. select()
/poll()
/당신이 무엇을 사용하는지.
#include <net/if.h>
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth1", sizeof(ifr.ifr_name));
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
(void *)&ifr, sizeof(ifr)) < 0) {
perror("SO_BINDTODEVICE failed");
}
(*노트)Bind()
인터페이스 IP 주소는 혼란 스럽지만 올바른 동작으로 이어질 수 있습니다. 예를 들어 당신이 bind()
ETH1의 IP 주소로, 라우팅 테이블은 패킷을 ETH0으로 전송하면 패킷이 ETH0 와이어에 나타나지 만 ETH1 인터페이스의 소스 IP 주소를 전달합니다. ETH1 IP 주소로 전송 된 패킷은 ETH1로 다시 라우팅됩니다. 두 개의 IP 인터페이스가있는 Linux 시스템을 사용 하여이 테스트 할 수 있습니다. 나는 하나가 있고 그것을 테스트했고 bind()
패킷을 물리적 인터페이스로 조종하는 데 효과적이지 않습니다.
기술적으로 허용되지만 토폴로지에 따라 그럼에도 불구하고 이것은 작동하지 않을 수 있습니다. 공격자가 단조 IP 소스 주소를 사용하는 분산 거부 공격 거부 공격을 약화시키기 위해 많은 라우터가 이제 RPF (Reverse Path Forwarding) 점검을 수행합니다. "잘못된"경로에 소스 IP 주소가있는 패킷을 삭제할 수 있습니다.