82 lines
2.7 KiB
C
82 lines
2.7 KiB
C
// commande : sudo ./send_eth <ifname> <dst-mac> <src-mac> <ethertype(hex)> <payload-as-string>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/if_packet.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/if.h>
|
|
|
|
static int mac_from_str(const char *s, unsigned char *mac) {
|
|
int vals[6];
|
|
if (sscanf(s, "%x:%x:%x:%x:%x:%x",
|
|
&vals[0], &vals[1], &vals[2],
|
|
&vals[3], &vals[4], &vals[5]) != 6) return -1;
|
|
for (int i = 0; i < 6; ++i) mac[i] = (unsigned char)vals[i];
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc < 6) {
|
|
fprintf(stderr, "Usage: %s <ifname> <dst-mac> <src-mac> <ethertype(hex)> <payload>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
const char *ifname = argv[1];
|
|
unsigned char dst_mac[6], src_mac[6];
|
|
if (mac_from_str(argv[2], dst_mac) < 0) { fprintf(stderr, "Bad dst-mac\n"); return 1; }
|
|
if (mac_from_str(argv[3], src_mac) < 0) { fprintf(stderr, "Bad src-mac\n"); return 1; }
|
|
|
|
unsigned int ethertype;
|
|
if (sscanf(argv[4], "%x", ðertype) != 1) { fprintf(stderr, "Bad ethertype\n"); return 1; }
|
|
|
|
const char *payload = argv[5];
|
|
size_t payload_len = strlen(payload);
|
|
|
|
int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
|
if (sock == -1) { perror("socket"); return 1; }
|
|
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
|
|
if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) { perror("SIOCGIFINDEX"); close(sock); return 1; }
|
|
int ifindex = ifr.ifr_ifindex;
|
|
|
|
unsigned char frame[ETH_FRAME_LEN];
|
|
size_t frame_len = 0;
|
|
|
|
memcpy(frame + frame_len, dst_mac, 6); frame_len += 6;
|
|
memcpy(frame + frame_len, src_mac, 6); frame_len += 6;
|
|
frame[frame_len++] = (ethertype >> 8) & 0xff;
|
|
frame[frame_len++] = ethertype & 0xff;
|
|
|
|
if (payload_len + frame_len > ETH_DATA_LEN + ETH_HLEN) {
|
|
fprintf(stderr, "Payload too large\n"); close(sock); return 1;
|
|
}
|
|
memcpy(frame + frame_len, payload, payload_len);
|
|
frame_len += payload_len;
|
|
|
|
if (frame_len < 60) {
|
|
memset(frame + frame_len, 0, 60 - frame_len);
|
|
frame_len = 60;
|
|
}
|
|
|
|
struct sockaddr_ll sock_addr;
|
|
memset(&sock_addr, 0, sizeof(sock_addr));
|
|
sock_addr.sll_ifindex = ifindex;
|
|
sock_addr.sll_halen = ETH_ALEN;
|
|
memcpy(sock_addr.sll_addr, dst_mac, 6);
|
|
|
|
ssize_t sent = sendto(sock, frame, frame_len, 0, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
|
|
if (sent == -1) { perror("sendto"); close(sock); return 1; }
|
|
|
|
printf("Sent %zd bytes on %s\n", sent, ifname);
|
|
close(sock);
|
|
return 0;
|
|
}
|