소켓이 메시지를받은 인터페이스를 알려주는 방법은 무엇입니까?
-
03-07-2019 - |
문제
소켓이 묶인 경우 IN6ADDR_ANY
또는 INADDR_ANY
그리고 당신은 다음과 같은 통화를 사용합니다 recvfrom()
소켓에 메시지를받습니다. 메시지가 어떤 인터페이스에서 왔는지 알아낼 수있는 방법이 있습니까?
IPv6 Link-Scope 메시지의 경우 recvfrom()
할 것입니다 scope_id
필드는 인터페이스 ID로 초기화되었습니다. 불행히도 그것은 설정됩니다 0
내 테스트 프로그램에서.
이 정보를 찾는 방법을 아는 사람이 있습니까?
해결책
각 인터페이스에 바인딩하는 것 외에도 IPv4 자체의 방법을 알지 못합니다.
IPv6 은이 단점을 해결하기 위해 IPv6_pktinfo 소켓 옵션을 추가했습니다. 사실상 그 옵션으로, a struct in6_pktinfo
보조 데이터로 반환됩니다.
다른 팁
DWC가 맞습니다. IPv6_pktinfo는 Linux에서 IPv6에서 작동합니다.
또한 IP_PKTINFO는 IPv4에서 작동합니다. Manpage IP (7)에서 세부 정보를 볼 수 있습니다.
소스, 대상 및 인터페이스 주소를 추출하는 예제를 구성했습니다. 간결성의 경우 오류 확인이 제공되지 않습니다. 이 복제본을 참조하십시오. 수신 된 UDP 패킷의 대상 주소를 얻으십시오.
// sock is bound AF_INET socket, usually SOCK_DGRAM
// include struct in_pktinfo in the message "ancilliary" control data
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));
// the control data is dumped here
char cmbuf[0x100];
// the remote/source sockaddr is put here
struct sockaddr_in peeraddr;
// if you want access to the data you need to init the msg_iovec fields
struct msghdr mh = {
.msg_name = &peeraddr,
.msg_namelen = sizeof(peeraddr),
.msg_control = cmbuf,
.msg_controllen = sizeof(cmbuf),
};
recvmsg(sock, &mh, 0);
for ( // iterate through all the control headers
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
cmsg != NULL;
cmsg = CMSG_NXTHDR(&mh, cmsg))
{
// ignore the control headers that don't match what we want
if (cmsg->cmsg_level != IPPROTO_IP ||
cmsg->cmsg_type != IP_PKTINFO)
{
continue;
}
struct in_pktinfo *pi = CMSG_DATA(cmsg);
// at this point, peeraddr is the source sockaddr
// pi->ipi_spec_dst is the destination in_addr
// pi->ipi_addr is the receiving interface in_addr
}
C/C ++ TCP/IP 코딩을해온 지 오래되었지만 모든 메시지 (또는 파생 된 소켓)에서 기억하는 한 IP 헤더 정보에 들어갈 수 있습니다. 이 헤더에는 요청하는 인터페이스의 IP가 될 수신 주소가 포함되어야합니다.
Glomek가 제안한대로 각 인터페이스에 별도의 소켓을 여는 것 외에는 Windows 에서이 작업을 수행하는 유일한 방법은 원시 소켓 (예 :)을 사용하는 것입니다.
SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
이 소켓에서 각각의 수신은 An이 될 것입니다 IP 패킷, 소스 및 대상 주소가 모두 포함되어 있습니다. 내가 작업하는 프로그램은 sio_rcvall 옵션을 사용하여 소켓을 무차별 모드로 넣어야합니다. 이렇게하면 네트워크에서 인터페이스가 "보는"모든 IP 패킷을 얻는다는 것을 의미합니다. 응용 프로그램을 위해 패킷을 명시 적으로 추출하려면 IP 및 TCP/UDP 헤더의 주소 및 포트를 사용하여 데이터를 필터링해야합니다. 분명히, 그것은 당신이 관심있는 것보다 더 많은 오버 헤드 일 것입니다. 나는 이것을 말하는 것만 언급합니다. 나는 무차별 모드에 넣지 않고 원시 소켓을 사용한 적이 없습니다. 따라서 inaddr_any에 바인딩 할 수 있는지 확실하지 않습니다. 그리고 그 시점에서 정규 소켓으로 사용할 수 있는지 확실하지 않습니다. 당신이 할 수있는 것은 나에게 보일 것입니다. 나는 그것을 시도한 적이 없다.
편집하다: 이것을 읽으십시오 기사 창의 원시 소켓에 대한 제한 사항. 내 프로젝트에서 직면 한이 가장 큰 장애물은 Windows 2000 이상에서 원시 소켓을 열기 위해 관리자 그룹의 구성원이어야한다는 것입니다.