-
-
Save kazkansouh/f68c62a9117b707b8be51ea5041dbfdb to your computer and use it in GitHub Desktop.
Send a raw Ethernet frame in Linux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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. | |
* | |
* Based off code from: | |
* https://gist.github.com/austinmarton/1922600 | |
* | |
* Modified to send hand crafted IPv6 NDP Neighbor | |
* Advertisements/Solicitations for petetration testing purposes. | |
* | |
* Note: all mac/ip addresses in payloads are examples only for | |
* illistartion of usage. | |
* | |
* | |
* Compile with: | |
* gcc -Wall -Wpedantic sendRawEth.c -o main | |
* | |
* Usage: | |
* ./main eth0 xx:xx:xx:xx:xx:xx | |
* where xx... is the destination mac address. | |
*/ | |
#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> | |
#include <inttypes.h> | |
#define DEFAULT_DEST_MAC "00:01:02:03:04:05" | |
#define DEFAULT_IF "eth0" | |
#define BUF_SIZ 1500 | |
/* Change below to select different ipv6 payload */ | |
#define IPv6_PAYLOAD packet_bytes_ns_custom_option | |
/* unicast ND-NS */ | |
uint8_t packet_bytes_ns[] = { | |
0x6e, 0x00, 0x00, 0x00, 0x00, | |
0x20, // payload length | |
0x3a, // next header | |
0xff, // hop count | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // source | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // destination | |
0x87, // ND-NS | |
0x00, // code | |
0xf7, 0x31, // checksum | |
0x00, 0x00, 0x00, 0x00, | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // target address | |
0x01, 0x01, 0x36, 0xf8, 0xcc, 0x39, 0x1d, 0x39 // source lla | |
}; | |
/* unicast ND-NS with non-standard option added */ | |
uint8_t packet_bytes_ns_custom_option[] = { | |
0x6e, 0x00, 0x00, 0x00, 0x00, | |
0x90, // payload length | |
0x3a, // next header | |
0xff, // hop count | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // source | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // destination | |
0x87, // ND-NS | |
0x00, // code | |
0x15, 0x43, // checksum | |
0x00, 0x00, 0x00, 0x00, | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // target address | |
// options | |
0x01, 0x01, 0x36, 0xf8, 0xcc, 0x39, 0x1d, 0x39, // source lla (8 bytes) | |
0xAA, 0x0E, // start custom option with 14 * 8 bytes | |
// data for custom option is an ipv6 icmp echo request | |
0x60, 0x09, 0x9d, 0x60, 0x00, 0x46, 0x3a, 0x40, | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x98, 0x00, 0x2c, 0xff, 0xfe, 0xfc, 0xa7, 0xfd, | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x55, | |
0x80, 0x00, 0xa1, 0x3d, 0x00, 0x56, 0x00, 0x01, | |
0x03, 0x03, 0x3f, 0x5c, 0x00, 0x00, 0x00, 0x00, | |
0x77, 0xb5, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | |
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | |
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | |
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, | |
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, | |
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d | |
}; | |
/* unicast ND-NA */ | |
uint8_t packet_bytes_na[] = { | |
0x6c, 0x00, 0x00, 0x00, 0x00, | |
0x20, // payload length | |
0x3a, // next header | |
0xff, // hop count | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // source | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // destination | |
// payload begin | |
0x88, // ND-NA | |
0x00, // code | |
0x15, 0x2c, // checksum | |
0xe0, 0x00, 0x00, 0x00, | |
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // target address | |
0x02, 0x01, 0x36, 0xf8, 0xcc, 0x39, 0x1d, 0x39 // target lla | |
}; | |
int parse_mac(const char* const mac, uint8_t* dest) { | |
return sscanf(mac, | |
"%02" SCNx8 ":" | |
"%02" SCNx8 ":" | |
"%02" SCNx8 ":" | |
"%02" SCNx8 ":" | |
"%02" SCNx8 ":" | |
"%02" SCNx8, | |
&dest[0], | |
&dest[1], | |
&dest[2], | |
&dest[3], | |
&dest[4], | |
&dest[5]) == 6; | |
} | |
int main(int argc, const char *argv[]) { | |
int sockfd; | |
struct ifreq if_idx; | |
struct ifreq if_mac; | |
int tx_len = 0; | |
uint8_t sendbuf[BUF_SIZ]; | |
struct ether_header *eh = (struct ether_header *) sendbuf; | |
struct sockaddr_ll socket_address; | |
char ifName[IFNAMSIZ]; | |
uint8_t dmac[6]; | |
/* Get interface name */ | |
if (argc > 1) | |
strcpy(ifName, argv[1]); | |
else | |
strcpy(ifName, DEFAULT_IF); | |
/* Set destination mac address */ | |
if (!parse_mac(argc > 2 ? argv[2] : DEFAULT_DEST_MAC, dmac)) { | |
perror("parse mac fail"); | |
} | |
/* 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]; | |
memcpy(eh->ether_dhost, dmac, 6); | |
/* Ethertype field */ | |
eh->ether_type = htons(ETH_P_IPV6); | |
tx_len += sizeof(struct ether_header); | |
/* Packet data */ | |
memcpy(sendbuf + tx_len, IPv6_PAYLOAD, sizeof(IPv6_PAYLOAD)); | |
tx_len += sizeof(IPv6_PAYLOAD); | |
/* Index of the network device */ | |
socket_address.sll_ifindex = if_idx.ifr_ifindex; | |
/* Address length*/ | |
socket_address.sll_halen = ETH_ALEN; | |
/* Destination MAC */ | |
memcpy(socket_address.sll_addr, dmac, 6); | |
/* Send packet */ | |
if (sendto(sockfd, | |
sendbuf, | |
tx_len, | |
0, | |
(struct sockaddr*)&socket_address, | |
sizeof(struct sockaddr_ll)) < 0) | |
printf("Send failed\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Modified to send hand crafted IPv6 NDP Neighbor Advertisements/Solicitations for penetration testing purposes.