2
votes

im stuck with sending a raw ethernet frame.

[edit]
I found some errors.
1. It has to be AF_PACKET in the socket call.
2. AF_PACKET doesnt have an option SOCK_PACKET, but SOCK_DGRAM and SOCK_RAW

With SOCK_DGRAM wireshark captures a malformed LLC packet.
But with SOCK_RAW no error message and no captured packet.

i dont find whats really going wrong.
[/edit]

the code:

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;
}

regards Ck

2
Are you running as root? Last time I looked (years ago) you had to have privileges to use raw sockets. - Jim Garrison

2 Answers

2
votes

I found the solution how this works. i took a look at the source code of the Linux program PackEth.

the following code works for me.

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;
}
0
votes
$ man 7 packet

"SOCK_RAW packets are passed to and from the device driver without any changes in the packet data. When receiving a packet, the address is still parsed and passed in a standard sockaddr_ll address structure. When transmitting a packet, the user supplied buffer should contain the physical layer header. That packet is then queued unmodified to the network driver of the interface defined by the destination address. Some device drivers always add other headers.

SOCK_DGRAM operates on a slightly higher level. The physical header is removed before the packet is passed to the user. Packets sent through a SOCK_DGRAM packet socket get a suitable physical layer header based on the information in the sockaddr_ll destination address before they are queued."