Skip to content

Instantly share code, notes, and snippets.

@kazkansouh
Forked from austinmarton/sendRawEth.c
Last active May 1, 2021 15:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kazkansouh/f68c62a9117b707b8be51ea5041dbfdb to your computer and use it in GitHub Desktop.
Save kazkansouh/f68c62a9117b707b8be51ea5041dbfdb to your computer and use it in GitHub Desktop.
Send a raw Ethernet frame in 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.
*
* 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;
}
@kazkansouh
Copy link
Author

Modified to send hand crafted IPv6 NDP Neighbor Advertisements/Solicitations for penetration testing purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment