소켓이 메시지를받은 인터페이스를 알려주는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/603577

  •  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 이상에서 원시 소켓을 열기 위해 관리자 그룹의 구성원이어야한다는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top