Raw packet program

Reference

https://stackoverflow.com/questions/21411851/how-to-send-data-over-a-raw-ethernet-socket-using-sendto-without-using-sockaddr

Example

#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <stdio.h>
#include <arpa/inet.h>

int main()
{
    char* ifname = "enp2s0";
    unsigned char srcMac[6];
    //unsigned char dstMac[6] = {0, 0xDE, 0xAD, 0xBE, 0xEF, 0};
    //00:e0:4c:68:3c:3b (enp3s0, 192.168.0.113)
    unsigned char dstMac[6] = {0, 0xE0, 0x4C, 0x68, 0x3C, 0x3B};
    int fd = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) );

     /* bind to interface */
    struct ifreq req;
    memset( &req, 0, sizeof( req ) );
    strcpy( (char*)req.ifr_name, (char*)ifname );

    if ( ioctl( fd, SIOCGIFINDEX, &req ) < 0 )
    {
        perror( "init: ioctl" );
        close( fd );
        return -1;
    }

    struct sockaddr_ll addr;
    memset( &addr, 0, sizeof( addr ) );
    addr.sll_family   = PF_PACKET;
    addr.sll_protocol = 0;
    addr.sll_ifindex  = req.ifr_ifindex;

    if ( bind( fd, (const struct sockaddr*)&addr, sizeof( addr ) ) < 0 )
    {
        perror( "init: bind fails" );
        close( fd );
        return -1;
    }

    if ( ioctl( fd, SIOCGIFHWADDR, &req ) < 0 )
    {
        perror( "init: ioctl SIOCGIFHWADDR" );
        close( fd );
        return -1;
    }

    /* store your mac address somewhere you'll need it! in your packet */
    memcpy( srcMac, (unsigned char*)req.ifr_hwaddr.sa_data, ETH_ALEN );

    int length = 60;
    unsigned char txPkt[ length ];
    unsigned char* pkt = txPkt;
    memset( txPkt, 0, sizeof( txPkt ) );

    //destination mac address
    memcpy( pkt, dstMac, 6 );
    pkt += 6;

    // source mac address
    memcpy( pkt, srcMac, 6 );
    pkt += 6;

    // add more data, like a type field!  etc

    int bytes = write( fd, txPkt, length );

    printf("Sent packet of size:%d\n", bytes);
    return 0;
}

/////////////version 2////////////////////////////////
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <stdio.h>
#include <arpa/inet.h>

int main()
{
    char* ifname = "enp2s0";
    unsigned char srcMac[6];
    //unsigned char dstMac[6] = {0, 0xDE, 0xAD, 0xBE, 0xEF, 0};
    //00:e0:4c:68:3c:3b (enp3s0, 192.168.0.113)
    unsigned char dstMac[6] = {0, 0xE0, 0x4C, 0x68, 0x3C, 0x3B};
    int fd = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) );

     /* bind to interface */
    struct ifreq req;
    memset( &req, 0, sizeof( req ) );
    strcpy( (char*)req.ifr_name, (char*)ifname );

    if ( ioctl( fd, SIOCGIFINDEX, &req ) < 0 )
    {
        perror( "init: ioctl" );
        close( fd );
        return -1;
    }

    struct sockaddr_ll addr;
    memset( &addr, 0, sizeof( addr ) );
    addr.sll_family   = PF_PACKET;
    addr.sll_protocol = 0;
    addr.sll_ifindex  = req.ifr_ifindex;

    if ( bind( fd, (const struct sockaddr*)&addr, sizeof( addr ) ) < 0 )
    {
        perror( "init: bind fails" );
        close( fd );
        return -1;
    }

    if ( ioctl( fd, SIOCGIFHWADDR, &req ) < 0 )
    {
        perror( "init: ioctl SIOCGIFHWADDR" );
        close( fd );
        return -1;
    }

    /* store your mac address somewhere you'll need it! in your packet */
    memcpy( srcMac, (unsigned char*)req.ifr_hwaddr.sa_data, ETH_ALEN );

    int length = 60;
    unsigned char txPkt[ length ];
    unsigned char* pkt = txPkt;
    memset( txPkt, 0, sizeof( txPkt ) );

    //destination mac address
    memcpy( pkt, dstMac, 6 );
    pkt += 6;

    // source mac address
    memcpy( pkt, srcMac, 6 );
    pkt += 6;

    // add more data, like a type field!  etc
    // etherType 0x0800
    unsigned char etherType[2] = {0x08, 0};
    memcpy( pkt, etherType, 2 );
    pkt += 2;

    unsigned char ip[20] = {0x45, 0, //ipv
                            0, 0x2E, //length 46
                            0x88, 0x1f, //ip-id
                            0x40, 0, //frag flag
                            0xf7, 0x11, //ttl, proto udp
                            0xea, 0x9d, //checksum
                            0x8, 0, 0, 0x1, // src IP 8.0.0.1
                            0x9, 0, 0, 0x1}; //dst IP 9.0.0.1
    memcpy( pkt, ip, 20 );
    pkt += 20;

    unsigned char udp[8] = {0x5a, 0x02, //src port
                            0x14, 0x7f, //dst port
                            0, 0x1A, //length 26
                            0, 0}; //checksum

    memcpy( pkt, udp, 8 );
    pkt += 8;

    //udp payload 18 bytes
    memset( pkt, 0xa5, 18 );

    //send packet
    int bytes = write( fd, txPkt, length );

    printf("Sent packet of size:%d\n", bytes);
    return 0;
}

Compile

gcc -o test raw_pkt.c

Test

sudo ./test
Sent packet of size:60

Tcpdump

09:23:21.663726 40:8d:5c:6f:99:6b > 00:e0:4c:68:3c:3b, 802.3, length 0: LLC, dsap Null (0x00) Individual, ssap Null (0x00) Command, ctrl 0x0000: Information, send seq 0, rcv seq 0, Flags [Command], length 46
        0x0000:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x0020:  0000 0000 0000 0000 0000 0000 0000       ..............


sudo tcpdump -eni enp3s0 ip host 8.0.0.1 -vv
tcpdump: listening on enp3s0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:22:07.215705 40:8d:5c:6f:99:6b > 00:e0:4c:68:3c:3b, ethertype IPv4 (0x0800), length 60: (tos 0x0, ttl 247, id 34847, offset 0, flags [DF], proto UDP (17), length 46)
    8.0.0.1.23042 > 9.0.0.1.5247: [no cksum] UDP, length 18

Leave a comment