2009-03-02 5 views
10

소켓이 IN6ADDR_ANY 또는 INADDR_ANY에 바인딩되어 있고 recvfrom()과 같은 호출을 사용하여 소켓에서 메시지를 수신하는 경우. 메시지가 어떤 인터페이스에서 왔는지 알아낼 방법이 있습니까?소켓이 메시지를 수신 한 인터페이스를 알려주는 방법은 무엇입니까?

IPv6 링크 범위 메시지의 경우 from 인수에 recvfrom()scope_id 필드가 인터페이스 ID로 초기화되기를 기대했습니다. 불행히도 내 테스트 프로그램에서는 0으로 설정되어 있습니다.

누구든지이 정보를 찾는 방법을 알고 있습니까?

답변

3

각 인터페이스에 바인딩하는 것 외에도, 나는 IPv4와 그 자체로 방법을 알지 못합니다.

IPv6는이 단점을 해결하기 위해 IPV6_PKTINFO 소켓 옵션을 추가했습니다. 해당 옵션을 적용하면 보조 데이터로 struct in6_pktinfo이 반환됩니다.

+0

감사합니다. 이것은 내가 찾고 있었던 것입니다. 여전히 Python 소켓 모듈에서는 지원되지 않습니다. 비록이 질문에서 libc를 지정했지만 말입니다. :) – Readonly

0

내가 C/C++ TCP/IP 코딩을해온 이래로 얼마 동안 있었지만 모든 메시지 (또는 파생 된 소켓)에서 IP 헤더 정보를 얻을 수있는 한 기억하고있다. 이 헤더에는 요청하는 인터페이스의 IP가 될 수신 주소가 포함되어야합니다.

-1
Glomek 제안으로, 각 인터페이스에 내가 Windows가 예를 들어 원시 소켓을 사용하는 것입니다에 결정적으로이 일을 알고있는 유일한 방법은 별도의 소켓을 여는

외부,

SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP); 

이 소켓에서 받게됩니다 IP packet이어야하며 원본 주소와 대상 주소를 모두 포함해야합니다. 내가 작업하는 프로그램은 SIO_RCVALL 옵션을 사용하여 무차별 모드로 소켓을 넣어야합니다. 이것은 인터페이스가 네트워크에서 "보는"모든 IP 패킷을 얻는다는 것을 의미합니다. 내 응용 프로그램에 대해 명시 적으로 패킷을 추출하려면 IP 및 TCP/UDP 헤더의 주소와 포트를 사용하여 데이터를 필터링해야합니다. 분명히, 그것은 아마도 여러분이 관심을 갖는 것보다 더 많은 오버 헤드가 될 것입니다. 나는 이것을 말할 때만 언급합니다. 난 원시 소켓을 무차별 모드로 두지 않고 결코 사용한 적이 없습니다. 그래서 만약 당신이 그것을 INADDR_ANY에 바인딩 할 수 있는지, 그냥 앞으로 그 지점에서 일반 소켓으로 사용할지 모르겠습니다. 네가 할 수있는 것은 나에게 보일 것이다. 나는 그것을 한번도 시도한 적이 없다.

편집 : Windows의 원시 소켓과 관련된 제한 사항은 article을 참조하십시오. 내 프로젝트에서 직면 한 가장 큰 장애물은 Windows 2000 이상의 원시 소켓을 열려면 Administrators 그룹의 구성원이어야한다는 것입니다.

7

dwc가 맞으면 IPV6_PKTINFO가 Linux에서 IPv6에 대해 작동합니다. 당신이 나는 소스, 대상 및 인터페이스 주소를 추출하는 예를 구축 한 맨의 IP (7)

+1

리눅스는 전세계가 아닙니다. 이식성 문제를 인식하는 것이 좋습니다. – dwc

+2

@dwc : 리눅스가 없다면 P를 에뮬레이트해야합니다 : P –

2

의 세부 정보를 볼 수 있습니다 -

또한, IP_PKTINFO는 IPv4에서 작동합니다. 간략하게하기 위해 오류 검사는 제공되지 않습니다. 이 사본을보십시오 : Get destination address of a received UDP packet.

// 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 
}