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).