raw ethernet sockets filling sockaddr_ll

13,791

You should probably use

socket(AF_PACKET, SOCK_DGRAM, htons(proto)))

instead of a SOCK_RAW socket. With a SOCK_RAW, you are sending/receiving the entire ethernet frame, including source and destination MAC address. with SOCK_DGRAM, the kernel will fill in the ethernet header.

You probably want to send the reply to the same address as the request comes from, recvfrom() can fill in the source address;

struct sockaddr_ll src_addr;
socklen_t addr_len = sizeof src_addr;
n = recvfrom(sckfd, buffer, 2048, 0, 
            (struct sockaddr*)&src_addr, &addr_len);

Now you've learned the source address, so send the packet back to it:

...
sendto(sckfd, data, data_len, src_addr, addr_len);

And if you rather need to use SOCK_RAW, your will receive the ethernet header too, so just copy out the MAC addresses from the received data and swap them around when you are constructing the reply frame.

For an a SOCK_RAW socket, you craft the entire ethernet frame, you don't need to fill in the ethernet address, so the following is not needed;

 memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);
Share:
13,791
user2948982
Author by

user2948982

Updated on June 04, 2022

Comments

  • user2948982
    user2948982 almost 2 years

    I am buliding a server/client software using PF_PACKET and SOCK_RAW and a custom protocol when calling socket()

    When in the client software I create the socket the same way and just do a rcvfrom that socket and I get the data

    My question is do I have to fill out the sockaddr_ll struct the same way I do for the server since when I reply from the client the source MAC address I got is a wierd one something like 11:11:00:00:00:00 and of course this is not my client's MAC

    Does anyone know what this happens? Open the socket

    if ( (sckfd=socket(PF_PACKET, SOCK_RAW, htons(proto)))<0)
    {
        myError("socket");
    
    }
    

    this is how I receive the data

    n = recvfrom(sckfd, buffer, 2048, 0, NULL, NULL);
    printf("%d bytes read\n",n);
    

    So this is how I basically receive the data in the client without filling the struct sockaddr_ll

    For the server Program I do have to fill the struct

    struct sockaddr_ll saddrll;
    memset((void*)&saddrll, 0, sizeof(saddrll));
    saddrll.sll_family = PF_PACKET;   
    saddrll.sll_ifindex = ifindex;
    saddrll.sll_halen = ETH_ALEN;
    memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);
    

    My question is I receive as shown and send as shown and when I reply to the server call the same function used in the server for Sending then what do I get 11:11:00:00:00:00 when receiving client replies

    • ryyker
      ryyker over 10 years
      would be an improvement to show some relevant code and describe this problem. (and is better than or)
    • user2948982
      user2948982 over 10 years
      The code is shown know ryyker3
  • user2948982
    user2948982 over 10 years
    Thanks I do need to use SOCK_RAW But that was a really good answer
  • thuovila
    thuovila over 10 years
    @nos Sorry if my question is dumb, but how do you figure AF_PACKET + SOCK_RAW uses struct sockaddr_pkt? Do you mean AF_INET+SOCK_RAW?
  • nos
    nos over 10 years
    By looking in the kernel sources. No I don't mean AF_INET+SOCK_RAW.
  • thuovila
    thuovila over 10 years
    @nos I think I see what you mean. I did not know that earlier. Though I think from an systemcall API point of view, the user could also use the userland struct msghdr with sendmsg() on a SOCK_RAW socket or am I still misunderstanding something?
  • nos
    nos over 10 years
    you can use sendmsg() or sendto()
  • user2948982
    user2948982 over 10 years
    Hi @thuovila I think you should take a look at this link hacked10bits.blogspot.com/2011/12/… it talks about sending and receiving ethernet frames
  • nos
    nos over 10 years
    I've deleted a couple of things. As it turns out a struct sockadd_pkt is used for a 3. type of raw ethernet socket, the AF_PACKET/SOCK_PACKET type. While both AF_PACKET/SOCK_RAW and AF_PACKET/SOCK_DGRAM uses a struct sockaddr_ll. It also seems for a AF_PACKET/SOCK_RAW you don't need to fill in the destination ethernet address in the struct sockaddr_ll (after all, you already set it in the frame you send)