Sending raw Ethernet packets from a specific interface in C on Linux
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)
(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 delay iph->id = htons(54321); iph->ttl = ttl; // hops iph->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; // skip tx_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");
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
http://aschauf.landshut.org/fh/linux/udp_vs_raw/ch01s03.html
http://www.tenouk.com/Module43a.html
http://linux.die.net/man/3/sendto
댓글 없음:
댓글 쓰기