Send a raw Ethernet frame in Linux (zz)

来源:互联网 发布:amt emulator mac 编辑:程序博客网 时间:2024/06/06 09:24

From here:

Send a raw Ethernet frame in Linux (GitHub)

Explanation is here

Sending raw Ethernet packets from a specific interface in C on Linux

packet, AF_PACKET - packet interface on device levelIn additionNote that this works only for some socket types, particularly AF_INET sockets.  It is not supported for packet sockets (use normal bind(2) there)Raw socket with device bind using setsockopt() system is not workingMore for UDPProgramming raw udp sockets in C on Linux

/** This program is free software: you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation, either version 3 of the License, or* (at your option) any later version.*/ #include <arpa/inet.h>#include <linux/if_packet.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <net/if.h>#include <netinet/ether.h> #define MY_DEST_MAC0 0x00#define MY_DEST_MAC1 0x00#define MY_DEST_MAC2 0x00#define MY_DEST_MAC3 0x00#define MY_DEST_MAC4 0x00#define MY_DEST_MAC5 0x00 #define DEFAULT_IF "eth0"#define BUF_SIZ 1024 int main(int argc, char *argv[]){int sockfd;struct ifreq if_idx;struct ifreq if_mac;int tx_len = 0;char sendbuf[BUF_SIZ];struct ether_header *eh = (struct ether_header *) sendbuf;struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));struct sockaddr_ll socket_address;char ifName[IFNAMSIZ];/* Get interface name */if (argc > 1)strcpy(ifName, argv[1]);elsestrcpy(ifName, DEFAULT_IF); /* Open RAW socket to send on */if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {perror("socket");} /* Get the index of the interface to send on */memset(&if_idx, 0, sizeof(struct ifreq));strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)perror("SIOCGIFINDEX");/* Get the MAC address of the interface to send on */memset(&if_mac, 0, sizeof(struct ifreq));strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)perror("SIOCGIFHWADDR"); /* Construct the Ethernet header */memset(sendbuf, 0, BUF_SIZ);/* Ethernet header */eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];eh->ether_dhost[0] = MY_DEST_MAC0;eh->ether_dhost[1] = MY_DEST_MAC1;eh->ether_dhost[2] = MY_DEST_MAC2;eh->ether_dhost[3] = MY_DEST_MAC3;eh->ether_dhost[4] = MY_DEST_MAC4;eh->ether_dhost[5] = MY_DEST_MAC5;/* Ethertype field */eh->ether_type = htons(ETH_P_IP);tx_len += sizeof(struct ether_header); /* Packet data */sendbuf[tx_len++] = 0xde;sendbuf[tx_len++] = 0xad;sendbuf[tx_len++] = 0xbe;sendbuf[tx_len++] = 0xef; /* Index of the network device */socket_address.sll_ifindex = if_idx.ifr_ifindex;/* Address length*/socket_address.sll_halen = ETH_ALEN;/* Destination MAC */socket_address.sll_addr[0] = MY_DEST_MAC0;socket_address.sll_addr[1] = MY_DEST_MAC1;socket_address.sll_addr[2] = MY_DEST_MAC2;socket_address.sll_addr[3] = MY_DEST_MAC3;socket_address.sll_addr[4] = MY_DEST_MAC4;socket_address.sll_addr[5] = MY_DEST_MAC5; /* Send packet */if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)printf("Send failed\n"); return 0;}

=======================

Lately I’ve been writing some code to send packets to a specific MAC address from a specific interface. I’m sure this will come in handy again so here is how it goes:

Includes:
(might not need all of these)

#include <netinet/in.h>#include <sys/socket.h>#include <arpa/inet.h>#include <net/if.h>#include <netinet/ip.h>#include <netinet/udp.h>#include <netinet/ether.h>#include <linux/if_packet.h>

Open the raw socket:

int sockfd;.../* Open RAW socket to send on */if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {    perror("socket");}

Get the index of the interface to send on:

struct ifreq if_idx;...memset(&if_idx, 0, sizeof(struct ifreq));strncpy(if_idx.ifr_name, "eth0", IFNAMSIZ-1);if (ioctl(sock, SIOCGIFINDEX, &if_idx) < 0)    perror("SIOCGIFINDEX");

Get the MAC address of the interface to send on:

struct ifreq if_mac;...memset(&if_mac, 0, sizeof(struct ifreq));strncpy(if_mac.ifr_name, "eth0", IFNAMSIZ-1);if (ioctl(sock, SIOCGIFHWADDR, &if_mac) < 0)    perror("SIOCGIFHWADDR");

Get the IP address of the interface to send on:

struct ifreq if_ip;...memset(&if_ip, 0, sizeof(struct ifreq));strncpy(if_ip.ifr_name, "eth0", IFNAMSIZ-1);if (ioctl(sock, SIOCGIFADDR, &if_ip) < 0)    perror("SIOCGIFADDR");

Construct the Ethernet header:

int tx_len = 0;char sendbuf[1024];struct ether_header *eh = (struct ether_header *) sendbuf;...memset(sendbuf, 0, 1024);/* Ethernet header */eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];eh->ether_dhost[0] = MY_DEST_MAC0;eh->ether_dhost[1] = MY_DEST_MAC1;eh->ether_dhost[2] = MY_DEST_MAC2;eh->ether_dhost[3] = MY_DEST_MAC3;eh->ether_dhost[4] = MY_DEST_MAC4;eh->ether_dhost[5] = MY_DEST_MAC5;eh->ether_type = htons(ETH_P_IP);tx_len += sizeof(struct ether_header);

Construct the IP header:

struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));.../* IP Header */iph->ihl = 5;iph->version = 4;iph->tos = 16; // Low delayiph->id = htons(54321);iph->ttl = ttl; // hopsiph->protocol = 17; // UDP/* Source IP address, can be spoofed */iph->saddr = inet_addr(inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr));// iph->saddr = inet_addr("192.168.0.112");/* Destination IP address */iph->daddr = inet_addr("192.168.0.111");tx_len += sizeof(struct iphdr);

Construct the UDP header:

struct udphdr *udph = (struct udphdr *) (sendbuf + sizeof(struct iphdr) + sizeof(struct ether_header));.../* UDP Header */udph->source = htons(3423);udph->dest = htons(5342);udph->check = 0; // skiptx_len += sizeof(struct udphdr);

Fill in UDP payload:

/* Packet data */sendbuf[tx_len++] = 0xde;sendbuf[tx_len++] = 0xad;sendbuf[tx_len++] = 0xbe;sendbuf[tx_len++] = 0xef;

Fill in remaining header info:

unsigned short csum(unsigned short *buf, int nwords){    unsigned long sum;    for(sum=0; nwords>0; nwords--)        sum += *buf++;    sum = (sum >> 16) + (sum &0xffff);    sum += (sum >> 16);    return (unsigned short)(~sum);}.../* Length of UDP payload and header */udph->len = htons(tx_len - sizeof(struct ether_header) - sizeof(struct iphdr));/* Length of IP payload and header */iph->tot_len = htons(tx_len - sizeof(struct ether_header));/* Calculate IP checksum on completed header */iph->check = csum((unsigned short *)(sendbuf+sizeof(struct ether_header)), sizeof(struct iphdr)/2);

Send the raw Ethernet packet:

/* Destination address */struct sockaddr_ll socket_address;.../* Index of the network device */socket_address.sll_ifindex = if_idx.ifr_ifindex;/* Address length*/socket_address.sll_halen = ETH_ALEN;/* Destination MAC */socket_address.sll_addr[0] = MY_DEST_MAC0;socket_address.sll_addr[1] = MY_DEST_MAC1;socket_address.sll_addr[2] = MY_DEST_MAC2;socket_address.sll_addr[3] = MY_DEST_MAC3;socket_address.sll_addr[4] = MY_DEST_MAC4;socket_address.sll_addr[5] = MY_DEST_MAC5;/* Send packet */if (sendto(sock, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)    printf("Send failed\n");

Update:
As in the comments, I’ve written a working example that can be found here: https://gist.github.com/1922600

Change the destination MAC address (e.g. 00:11:22:33:44:55) and compile:

gcc sendRawEth.c -o sendRawEth

In one terminal run tcpdump to observe the packets:

sudo tcpdump -nettti eth0 '(ether dst host 00:11:22:33:44:55)'

And in another run the program as root:

sudo ./sendRawEth eth0

References:
http://aschauf.landshut.org/fh/linux/udp_vs_raw/ch01s03.html
http://www.tenouk.com/Module43a.html
http://linux.die.net/man/3/sendto


=====================================

void BindToInterface(int raw , char *device , int protocol) {     struct sockaddr_ll sll;    struct ifreq ifr; bzero(&sll , sizeof(sll));    bzero(&ifr , sizeof(ifr));     strncpy((char *)ifr.ifr_name ,device , IFNAMSIZ);     //copy device name to ifr     if((ioctl(raw , SIOCGIFINDEX , &ifr)) == -1)    {         perror("Unable to find interface index");        exit(-1);     }    sll.sll_family = AF_PACKET;     sll.sll_ifindex = ifr.ifr_ifindex;     sll.sll_protocol = htons(protocol);     if((bind(raw , (struct sockaddr *)&sll , sizeof(sll))) ==-1)    {        perror("bind: ");        exit(-1);    }    return 0;} 



0 0
原创粉丝点击