Skip to content

Instantly share code, notes, and snippets.

@dterei
Last active August 29, 2015 14:16
Show Gist options
  • Save dterei/b75a69be63c707f800c3 to your computer and use it in GitHub Desktop.
Save dterei/b75a69be63c707f800c3 to your computer and use it in GitHub Desktop.
Send packet via macvtap device
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <net/if.h>
#include <netinet/in.h>
#define ETH_HDRLEN ETH_HLEN
#define IP4_HDRLEN (sizeof(struct iphdr))
#define UDP_HDRLEN (sizeof(struct udphdr))
#define HOST_IF "mvt1"
#define HOST_IP "10.0.1.54"
#define DEST_IP "179.32.32.11"
#define HOST_PORT 7000
#define DEST_PORT 8000
#define MAC_SRC { 0xbc, 0xae, 0xc5, 0x44, 0x3d, 0x46 } │···································
#define MAC_DST { 0x52, 0x54, 0x00, 0x26, 0xc1, 0x45 }
#define PAYLOAD "Hello World!\n"
void usage(char* proc)
{
printf("usage: %s [vtap device]\n", proc);
}
size_t build_packet(uint8_t *pkt, size_t pkt_buf_len)
{
// Sizes
size_t hdr_len = ETH_HDRLEN + IP4_HDRLEN + UDP_HDRLEN;
uint16_t data_len = strlen(PAYLOAD);
size_t pkt_len = hdr_len + data_len;
if (pkt_len > pkt_buf_len) {
fprintf(stderr, "packet buffer too small! (%lu vs %lu)\n", pkt_len, pkt_buf_len);
exit(EXIT_FAILURE);
}
// Packet
struct ether_header *ethhdr = (struct ether_header *) pkt;
struct iphdr *iphdr = (struct iphdr *) (pkt + ETH_HDRLEN);
struct udphdr *udphdr = (struct udphdr *) (pkt + ETH_HDRLEN + IP4_HDRLEN);
uint8_t *payload = pkt + hdr_len;
// Ethernet header
uint8_t mac_dest[] = MAC_DST;
ethhdr->ether_dhost[0] = mac_dest[0];
ethhdr->ether_dhost[1] = mac_dest[1];
ethhdr->ether_dhost[2] = mac_dest[2];
ethhdr->ether_dhost[3] = mac_dest[3];
ethhdr->ether_dhost[4] = mac_dest[4];
ethhdr->ether_dhost[5] = mac_dest[5];
uint8_t mac_source[] = MAC_SRC;
ethhdr->ether_shost[0] = mac_src[0];
ethhdr->ether_shost[1] = mac_src[1];
ethhdr->ether_shost[2] = mac_src[2];
ethhdr->ether_shost[3] = mac_src[3];
ethhdr->ether_shost[4] = mac_src[4];
ethhdr->ether_shost[5] = mac_src[5];
ethhdr->ether_type = htons(ETH_P_IP);
// IPv4 header
iphdr->version = 4;
iphdr->ihl = 5;
iphdr->tos = 0;
iphdr->tot_len = htons(IP4_HDRLEN + UDP_HDRLEN + data_len);
iphdr->id = htons(8318);
iphdr->frag_off = 0;
iphdr->ttl = 255;
iphdr->protocol = IPPROTO_UDP;
iphdr->check = 0;
iphdr->saddr = inet_addr(HOST_IP);
iphdr->daddr = inet_addr(DEST_IP);
// IP Checksum
iphdr->check = internet_checksum(pkt + ETH_HDRLEN, IP4_HDRLEN);
// UDP header
udphdr->source = htons(HOST_PORT);
udphdr->dest = htons(DEST_PORT);
udphdr->len = htons(UDP_HDRLEN + data_len);
udphdr->check = 0;
// Payload
memcpy (payload, PAYLOAD, data_len);
return pkt_len;
}
int tap_set_sndbuf(int fd)
{
int sndbuf = 1024 * 1024;
if (ioctl(fd, TUNSETSNDBUF, &sndbuf) < 0) {
perror("ioctl(TUNSETSNDBUF)");
return -1;
}
return 0;
}
int main(int argc, char* argv[])
{
int err, vtap;
uint8_t pkt[IP_MAXPACKET];
size_t pkt_len;
if (argc != 2) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
// open ('/dev/tap3', ...);
if ((vtap = open(argv[1], O_RDWR)) < 0) {
perror("Failure to open vtap device");
exit(EXIT_FAILURE);
}
if (tap_set_sndbuf(vtap) < 0) {
exit(EXIT_FAILURE);
}
// Build packet
pkt_len = build_packet(pkt, IP_MAXPACKET);
if (pkt_len < 0) {
perror("build_packet()");
exit(EXIT_FAILURE);
}
// Send packet
if ((err = write(vtap, pkt, pkt_len)) < 0) {
perror("write()");
printf("err: %d\n", errno);
exit(EXIT_FAILURE);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment