2009-03-02 55 views
10

Nếu ổ cắm bị ràng buộc đến IN6ADDR_ANY hoặc INADDR_ANY và bạn sử dụng một cuộc gọi như recvfrom() để nhận tin nhắn trên ổ cắm. Có cách nào để tìm ra giao diện thông điệp đến từ đâu không?Làm cách nào để biết giao diện nào nhận được tin nhắn từ?

Trong trường hợp thông báo phạm vi liên kết IPv6, tôi đã hy vọng rằng đối số từ recvfrom() sẽ có trường scope_id được khởi tạo cho Id giao diện. Rất tiếc, nó được đặt thành 0 trong chương trình thử nghiệm của tôi.

Bất kỳ ai biết cách tìm hiểu thông tin này?

Trả lời

3

Ngoài việc ràng buộc với mỗi giao diện, tôi không biết cách nào với IPv4, mỗi lần truy cập.

IPv6 đã thêm tùy chọn ổ cắm IPV6_PKTINFO để giải quyết thiếu sót này. Với tùy chọn đó có hiệu lực, struct in6_pktinfo sẽ được trả về dưới dạng dữ liệu phụ trợ.

+0

Cảm ơn, đây là những gì tôi đang tìm kiếm. Quá tệ nó không được mô-đun của socket Python hỗ trợ - mặc dù tôi đã chỉ định libc trong câu hỏi này. :) – Readonly

0

Đã một thời gian kể từ khi tôi đang thực hiện mã hóa TCP/IP C/C++ nhưng theo như tôi nhớ trên mọi thư (hoặc ổ cắm dẫn xuất), bạn có thể nhận được thông tin tiêu đề IP. Các tiêu đề này phải bao gồm địa chỉ nhận sẽ là IP của giao diện bạn đang hỏi.

-1

Bên ngoài mở một ổ cắm riêng biệt trên mỗi giao diện như Glomek gợi ý, cách duy nhất mà tôi biết để làm được điều này dứt khoát trên Windows là sử dụng một ổ cắm nguyên, ví dụ:

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

Mỗi nhận được từ ổ cắm này sẽ là một IP packet, chứa cả địa chỉ nguồn và đích. Chương trình tôi làm việc trên đòi hỏi tôi phải đặt socket trong chế độ promiscuous bằng cách sử dụng tùy chọn SIO_RCVALL. Làm điều này có nghĩa là tôi nhận được mọi gói IP giao diện "nhìn thấy" trên mạng. Để trích xuất các gói một cách rõ ràng cho ứng dụng của tôi yêu cầu tôi lọc dữ liệu bằng cách sử dụng các địa chỉ và cổng trong tiêu đề IP và TCP/UDP. Rõ ràng, đó có lẽ là chi phí cao hơn bạn quan tâm. Tôi chỉ đề cập đến nó để nói điều này - Tôi chưa bao giờ sử dụng một ổ cắm thô mà không đặt nó trong chế độ promiscuous. Vì vậy, tôi không chắc chắn nếu bạn có thể liên kết nó với INADDR_ANY và chỉ sử dụng nó như một ổ cắm thông thường từ điểm đó về phía trước hay không. Dường như với tôi rằng bạn có thể; Tôi chưa bao giờ thử nó.

EDIT: Đọc này article để biết giới hạn về ổ cắm thô trên Windows. Trở ngại lớn nhất mà tôi phải đối mặt trong dự án của tôi là người ta phải là thành viên của nhóm Quản trị viên để mở một ổ cắm thô trên Windows 2000 trở lên.

7

dwc là đúng, IPV6_PKTINFO sẽ hoạt động cho IPv6 trên Linux.

Hơn nữa, IP_PKTINFO sẽ làm việc cho IPv4 - bạn có thể xem chi tiết trong manpage ip (7)

+1

Linux không phải là toàn thế giới. Bạn nên biết các vấn đề về tính di động. – dwc

+2

@dwc: Nếu bạn không có Linux, bạn nên mô phỏng nó: P –

2

tôi đã xây dựng một ví dụ để trích ra phần địa chỉ nguồn, đích và giao diện. Đối với ngắn gọn, không có kiểm tra lỗi được cung cấp. Xem bản sao này: 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 
} 
Các vấn đề liên quan