• 请不要在回答技术问题时复制粘贴 AI 生成的内容
F32
V2EX  ›  程序员

使用 Raw Socket 时如何自动获取 Source Address?

  •  
  •   F32 · Jun 3, 2015 · 3704 views
    This topic created in 4022 days ago, the information mentioned may be changed or developed.

    使用普通的 Socket 时,一般由操作系统负责查询本地的路由表,自动填写 IP 报文里的 Source Address 字段,应用程序不用关心用的是哪个本机 IP(很多网络程序是不用绑定端口的)。

    但是有些情况下可能需要使用 Raw Socket,并且需要手动填写 IP 报文里的 Source Address 字段。请问是否有相关的命令 / 系统 API 能够完成这个步骤?必须要用户来指定太不智能了。

    8 replies    2015-06-23 15:30:54 +08:00
    est
        1
    est  
       Jun 3, 2015
    getaddrinfo 这个?
    F32
        2
    F32  
    OP
       Jun 3, 2015
    @est 我的问题的本质是路由表查询,getaddrinfo 好像没有处理这个问题把?
    fangjinmin
        3
    fangjinmin  
       Jun 3, 2015
    多网卡的时候,只能手动填写吧。
    fangdingjun
        4
    fangdingjun  
       Jun 3, 2015   ❤️ 1
    这里有变通的方法啊
    先建一个普通的udp socket,然后connect目标地址,就可以获取到source address了,把这个source address用于raw socket就行了
    TheCure
        5
    TheCure  
       Jun 3, 2015
    需要先指定Interface 返回Interface的地址 然后构造数据包 然后协议栈会根据目的地址匹配路由表 不知道src address和路由表有什么关系
    gamexg
        6
    gamexg  
       Jun 3, 2015
    @callofmx 楼主的意思是本地有多个ip的时候,不确定对应目的地址使用哪个本地IP。

    不过除非非常复杂的网络环境下开发,一般直接用默认路由同网段的就行。

    @fangdingjun 真是个好主意。
    F32
        7
    F32  
    OP
       Jun 23, 2015
    @fangdingjun 方法经测试可用,非常感谢。为了方便其他可能遇到问题的人,这里贴上代码(Linux)

    #include <stdio.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>

    int main()
    {
    &nbsp;&nbsp;&nbsp;&nbsp;// create socket
    &nbsp;&nbsp;&nbsp;&nbsp;int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
    &nbsp;&nbsp;&nbsp;&nbsp;if (sockfd < 0)
    &nbsp;&nbsp;&nbsp;&nbsp;{
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("create_socket()");
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;
    &nbsp;&nbsp;&nbsp;&nbsp;}

    &nbsp;&nbsp;&nbsp;&nbsp;// prepare target address
    &nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in addr;
    &nbsp;&nbsp;&nbsp;&nbsp;memset(&addr, 0, sizeof(addr));
    &nbsp;&nbsp;&nbsp;&nbsp;addr.sin_family = AF_INET;
    &nbsp;&nbsp;&nbsp;&nbsp;addr.sin_addr.s_addr = inet_addr("8.8.8.8");
    &nbsp;&nbsp;&nbsp;&nbsp;addr.sin_port = htons(33435);

    &nbsp;&nbsp;&nbsp;&nbsp;// connect
    &nbsp;&nbsp;&nbsp;&nbsp;connect(sockfd, (sockaddr *)&addr, sizeof(addr));

    &nbsp;&nbsp;&nbsp;&nbsp;// prepare local address
    &nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in local_addr;
    &nbsp;&nbsp;&nbsp;&nbsp;unsigned int len = sizeof(local_addr);
    &nbsp;&nbsp;&nbsp;&nbsp;getsockname(sockfd, (sockaddr *)&local_addr, &len);

    &nbsp;&nbsp;&nbsp;&nbsp;// output
    &nbsp;&nbsp;&nbsp;&nbsp;printf("local address: %s\n", inet_ntoa(local_addr.sin_addr));

    &nbsp;&nbsp;&nbsp;&nbsp;return 0;
    }
    F32
        8
    F32  
    OP
       Jun 23, 2015
    -_-

    #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;
    }
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   6081 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 95ms · UTC 03:16 · PVG 11:16 · LAX 20:16 · JFK 23:16
    ♥ Do have faith in what you're doing.