【问题标题】:Injecting raw packet onto network in C (Linux)在 C (Linux) 中将原始数据包注入网络
【发布时间】:2014-11-18 21:06:48
【问题描述】:

我正在尝试编写一个函数,该函数接受字节流(包括以太网标头,也许还包括封装在以太网数据包中的上层协议),并通过特定接口将其发送到网络上。

以下是我的代码摘要:

// create socket
int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) {
    // error handling
}

// set up to just receive/send packets on one interface (stored in the variable iface_name e.g. eth0)
struct ifreq ifr;
bzero(&ifr, sizeof(struct ifreq));
strncpy(ifr.ifr_ifrn.ifrn_name, iface_name, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
    // error handling
}

// set up socaddr for write
struct sockaddr sa;
sa.sa_family = PF_PACKET;
sa.sa_data = htons(ETH_P_ALL);

// write to wire
// buf has type char* and len has type int
// buf contains ethernet header, followed by payload (e.g. ARP packet or IP packet)
if ( sendto(s, buf, len, 0, &sa, sizeof(struct sockaddr) ) < 0 ) {
    perror("sendto");
    // more error handling
}

我得到了错误

sendto: Invalid argument

我该如何解决这个错误?

我最初的猜测是,这在某种程度上是由 sa 参数引起的,因为所有其他参数都是相当标准的,并且不会出错。我可以用sockaddr_ll 类型的参数替换它,就像this example 一样,但这意味着从buf 中提取标题信息,这似乎有点毫无意义,因为它已经在那里,准备好了。一定会有更好的办法?封装、取消封装、重新封装、发送似乎有太多不必要的步骤。我正在为一些预先存在的代码编写一个底层接口,所以我无法调整输入以不包含数据链路层标头。

【问题讨论】:

  • 我觉得差不多了,但是sll_addr中的目的MAC地址要填什么呢?如果可能的话,我想避免从我的输入数据中提取它(因为数据包已经构建,所以我不明白为什么我必须把它拆开)。我想我明白这是否不可能?
  • 所以你是说在你发送的示例链接中的MY_DEST_MAC中,我填写的是我自己的MAC地址?这似乎有点违反直觉,因为我没有将帧发送给自己。我什至必须填写 MAC 地址这一事实让我认为该卡将进行一些我不想要的额外封装?
  • en.wikipedia.org/wiki/Ethernet_frame。是的,你放了你自己的mac地址(路由器怎么会知道把它发回给你?)它的工作方式是,你放一个源ip和一个目标ip,然后你放一个源mac地址(你的) ,然后你把你的路由器的mac地址作为目的地。然后路由器拿到后,保留源ip和目的ip,只是把mac地址改成自己的作为源,然后作为next路由器作为mac地址。这种情况一直发生,直到数据包到达目的地。

标签: c sockets data-link-layer


【解决方案1】:

它是你的库:

http://linux.die.net/man/7/raw 见标题定义 看看他是如何制作插座的 他没有使用 hton,而是: IPPROTO_RAW 位于

  #include <netinet/in.h>

【讨论】:

    猜你喜欢
    • 2013-01-02
    • 2019-03-07
    • 2011-05-11
    • 1970-01-01
    • 2012-10-13
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多