使用普通的 Socket 时,一般由操作系统负责查询本地的路由表,自动填写 IP 报文里的 Source Address 字段,应用程序不用关心用的是哪个本机 IP(很多网络程序是不用绑定端口的)。
但是有些情况下可能需要使用 Raw Socket,并且需要手动填写 IP 报文里的 Source Address 字段。请问是否有相关的命令 / 系统 API 能够完成这个步骤?必须要用户来指定太不智能了。
1
est 2015-06-03 12:43:00 +08:00
getaddrinfo 这个?
|
3
fangjinmin 2015-06-03 15:28:46 +08:00
多网卡的时候,只能手动填写吧。
|
4
fangdingjun 2015-06-03 15:35:14 +08:00 1
这里有变通的方法啊
先建一个普通的udp socket,然后connect目标地址,就可以获取到source address了,把这个source address用于raw socket就行了 |
5
TheCure 2015-06-03 16:19:19 +08:00
需要先指定Interface 返回Interface的地址 然后构造数据包 然后协议栈会根据目的地址匹配路由表 不知道src address和路由表有什么关系
|
6
gamexg 2015-06-03 16:42:38 +08:00
|
7
F32 OP @fangdingjun 方法经测试可用,非常感谢。为了方便其他可能遇到问题的人,这里贴上代码(Linux)
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> int main() { // create socket int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); if (sockfd < 0) { perror("create_socket()"); return -1; } // prepare target address sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("8.8.8.8"); addr.sin_port = htons(33435); // connect connect(sockfd, (sockaddr *)&addr, sizeof(addr)); // prepare local address sockaddr_in local_addr; unsigned int len = sizeof(local_addr); getsockname(sockfd, (sockaddr *)&local_addr, &len); // output printf("local address: %s\n", inet_ntoa(local_addr.sin_addr)); return 0; } |
8
F32 OP -_-
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> int main() { // create socket int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); if (sockfd < 0) { perror("create_socket()"); return -1; } // prepare target address sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("8.8.8.8"); addr.sin_port = htons(33435); // connect connect(sockfd, (sockaddr *)&addr, sizeof(addr)); // prepare local address sockaddr_in local_addr; unsigned int len = sizeof(local_addr); getsockname(sockfd, (sockaddr *)&local_addr, &len); // output printf("local address: %s\n", inet_ntoa(local_addr.sin_addr)); return 0; } |