sendto的原始套接字错误:没有错误代码[was:带有sendto的原始套接字错误:没有这样的设备]

时间:2012-10-10 03:19:34

标签: c++ linux raw-sockets

我坚持发送一个原始的以太网帧。

[编辑]
我发现了一些错误 1.套接字调用中必须是AF_PACKET 2. AF_PACKET没有SOCK_PACKET选项,但是SOCK_DGRAM和SOCK_RAW

使用SOCK_DGRAM wireshark捕获格式错误的LLC数据包 但是SOCK_RAW没有错误消息,也没有捕获的数据包。

我没有发现什么事情真的出错 [/ edit]

代码:

if ((ethernet_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1)
    cout << "Ethernet Socket: "<< strerror(errno) << endl;

struct sockaddr_ll socket_address;
socket_address.sll_family   = PF_PACKET;
socket_address.sll_protocol = htons(ETH_P_IP);
socket_address.sll_ifindex=if_nametoindex("eth0");
socket_address.sll_hatype   = 1; // ARPHRD_ETHER
socket_address.sll_pkttype  = PACKET_OTHERHOST;
socket_address.sll_halen    = ETH_ALEN;
memcpy(socket_address.sll_addr,dest_mac_addr,ETH_ALEN);

int send_result = 0;

char *opt=(char*)malloc(4*sizeof(char));
strcpy(opt,"eth0");

if(setsockopt(ethernet_socket, SOL_SOCKET, SO_BINDTODEVICE, opt, 4)==-1)
    cout << "Could not bind socket to device: " << strerror(errno) << endl;

if ((send_result  
= sendto(ethernet_socket, &buffer, sizeof(buffer), 0,  
    (struct sockaddr*)&socket_address, sizeof(socket_address)))==-1){
        cout << "sendto error: "<< strerror(errno) << endl;
        return send_result;
}

问候 CK

2 个答案:

答案 0 :(得分:2)

我找到了解决方案是如何工作的。 我看了一下Linux程序PackEth的源代码。

以下代码适用于我。

if ((ethernet_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1)
    cout << "Ethernet Socket: "<< strerror(errno) << endl;  //errorhandling

memset(&ifr, 0, sizeof(ifr));
strncpy (ifr.ifr_name, "eth0", sizeof(ifr.ifr_name) - 1);
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';


if (ioctl(ethernet_socket, SIOCGIFINDEX, &ifr) == -1) {
    cout << "No such interface:"<< strerror(errno) << endl;
    close(ethernet_socket);
}

ioctl(ethernet_socket, SIOCGIFFLAGS, &ifr);
if ( (ifr.ifr_flags & 0x1) == 0) {
    cout << "Interface is down: "<< strerror(errno) << endl;
    close(ethernet_socket);
}

ioctl(ethernet_socket, SIOCGIFINDEX, &ifr);


memset(&socket_address, 0, sizeof (socket_address));
socket_address.sll_family    = AF_PACKET;
socket_address.sll_ifindex   = ifr.ifr_ifindex;
socket_address.sll_protocol  = htons(ETH_P_ALL);

if ((raw_send = sendto(ethernet_socket, buffer, size_payload+14,0,(struct     sockaddr*)     
                           &socket_address, sizeof(socket_address)))==-1){
    cout << "sendto error: "<< strerror(errno) << endl;
    return raw_send;
}

答案 1 :(得分:0)

$ man 7 packet

&#34; SOCK_RAW数据包传入和传出设备驱动程序,而不会对数据包数据进行任何更改。接收数据包时,仍会解析地址并将其传递到标准的sockaddr_ll地址结构中。 传输数据包时,用户提供的缓冲区应包含物理层标题。然后,该数据包未经修改地排队到由目标地址定义的接口的网络驱动程序。某些设备驱动程序总是添加其他标题。

SOCK_DGRAM的运行水平略高。在将数据包传递给用户之前删除物理标头。 通过SOCK_DGRAM数据包套接字发送的数据包在排队之前根据sockaddr_ll目标地址中的信息获取合适的物理层标头。&#34;