Home > Blockchain >  Layer 2 socket programming
Layer 2 socket programming

Time:08-31

I'm trying to connect to a device just with its mac address. I'm working on Linux-Ubuntu with c language. First I wanna send a simple packet broadcasting so I set destination address to ff:ff:ff:ff:ff:ff. My laptop is connected to a tp-link socket and no other devices connected to it. Maybe I have no enough information about socket programming. Please help me. Why "errno" is 22(Invalid argument)? The code that I have tested it is as follow. I run it as sudo.

A note: When I change "SOCK_RAW" to "SOCK_DGRAM" it works well. Why "SOCK_RAW" doesn't work?

Output is:

Address setted:
address[0]: ffffffff
address[1]: ffffffff
address[2]: ffffffff
address[3]: ffffffff
address[4]: ffffffff
address[5]: ffffffff
InterfaceIndex detected: 2
Opening a socket done.
Setting multicast address done.
Result: -1
errno: 22

Code:

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <errno.h>

#define true 1
#define false 0

typedef char bool;

struct socket_address
{
    int sll_ifindex;
    int sll_hatype;
    int sll_pkttype;
    int sll_halen;
};

struct sEthernetSocket {
    int rawSocket;
    bool isBind;
    struct sockaddr_ll socketAddress;
};

typedef struct sEthernetSocket *EthernetSocket;



static int getInterfaceIndex(int sock, const char* deviceName)
{
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(struct ifreq));

    strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);

    if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) {
        printf("ETHERNET_LINUX: Failed to get interface index\n");
        return -1;
    }
    else {
        printf("InterfaceIndex detected: %d\n", ifr.ifr_ifindex);
    }

    int interfaceIndex = ifr.ifr_ifindex;

    return interfaceIndex;
}

void Ethernet_destroySocket(EthernetSocket ethSocket)
{
    close(ethSocket->rawSocket);
    free(ethSocket);
}

EthernetSocket Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress)
{
    EthernetSocket ethernetSocket = calloc(1, sizeof(struct sEthernetSocket));

    if (ethernetSocket) {
        ethernetSocket->rawSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

        if (ethernetSocket->rawSocket == -1) {
            printf("Error creating raw socket!\n");
            free(ethernetSocket);
            return NULL;
        }

        ethernetSocket->socketAddress.sll_family = PF_PACKET;
        ethernetSocket->socketAddress.sll_protocol = htons(ETH_P_ALL);

        int ifcIdx =  getInterfaceIndex(ethernetSocket->rawSocket, interfaceId);

        if (ifcIdx == -1) {
            Ethernet_destroySocket(ethernetSocket);
            return NULL;
        }

        ethernetSocket->socketAddress.sll_ifindex = ifcIdx;

        ethernetSocket->socketAddress.sll_hatype =  ARPHRD_ETHER;
        ethernetSocket->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST;

        ethernetSocket->socketAddress.sll_halen = ETH_ALEN;

        memset(ethernetSocket->socketAddress.sll_addr, 0, 8);

        if (destAddress != NULL){
            memcpy(ethernetSocket->socketAddress.sll_addr, destAddress, 6);
        }

        ethernetSocket->isBind = false;
    }

    return ethernetSocket;
}

int Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize)
{
    return sendto(ethSocket->rawSocket, buffer, packetSize,
               0, (struct sockaddr*) &(ethSocket->socketAddress), sizeof(ethSocket->socketAddress));
    // return write(ethSocket->rawSocket, buffer, strlen(buffer)); 

}

void
Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr)
{
    struct ifreq buffer;

    int sock = socket(PF_INET, SOCK_DGRAM, 0);

    memset(&buffer, 0x00, sizeof(buffer));

    strncpy(buffer.ifr_name, interfaceId, IFNAMSIZ - 1);

    ioctl(sock, SIOCGIFHWADDR, &buffer);

    close(sock);

    int i;

    for(i = 0; i < 6; i   )
    {
        addr[i] = (unsigned char)buffer.ifr_hwaddr.sa_data[i];
    }
}

void
Ethernet_addMulticastAddress(EthernetSocket ethSocket, uint8_t* multicastAddress)
{
    struct packet_mreq mreq;
    mreq.mr_ifindex = ethSocket->socketAddress.sll_ifindex;
    mreq.mr_alen = ETH_ALEN;
    mreq.mr_type = PACKET_MR_MULTICAST;
    mreq.mr_address[0] = multicastAddress[0];
    mreq.mr_address[1] = multicastAddress[1];
    mreq.mr_address[2] = multicastAddress[2];
    mreq.mr_address[3] = multicastAddress[3];
    mreq.mr_address[4] = multicastAddress[4];
    mreq.mr_address[5] = multicastAddress[5];

    int res = setsockopt(ethSocket->rawSocket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));


    if (res != 0) {
        printf("ETHERNET_LINUX: Setting multicast address failed");
    }
}


int main(){
    //-------------------------Setting destination address-------------------------//
    char address[100];
    //Ethernet_getInterfaceMACAddress("enp2s0", &address);
    for(int i = 0; i < 6; i  )address[i] = 0xff;
    printf("Address setted:\n");
    for(int i = 0; i < 6; i  )printf("address[%d]: %x\n",i , address[i]);
    //-------------------------------Opening a socket------------------------------//
    EthernetSocket ethSocket = Ethernet_createSocket("enp2s0", address);
    if(ethSocket) printf("Opening a socket done.\n");
    else printf("Error opening a socket.\n");
    //--------------------------Setting multicast address--------------------------//
    Ethernet_addMulticastAddress(ethSocket, address);
    printf("Setting multicast address done.\n");
    //---------------------------------Sending data--------------------------------//
    int res = Ethernet_sendPacket(ethSocket, "Hello", 6);
    printf("Result: %d\nerrno: %d\n", res, errno);

   
}

CodePudding user response:

I found problem. I must send a correct data when I use SOCK_RAW. "Hello" is incorrect and meaningless. Correct data includes "destination mac address" "source mac address" "ethertype/size" "payload". I mean it must be according to the Ethernet frame (Ether type).

  • Related