User Controls

C raw TCP packet, including headers

  1. #1
    SBTlauien African Astronaut
    I've come across the code below that'll make and send a TCP packet. It's not just creating a socket, connecting to a port, and using buffers to read/write data, it actually allows creation of the IP header and TCP header. The codes works as I've checked it on WireShark, but it doesn't send any data within the packet. I want to add some data to the packet but I don't know how to.


    #include <unistd.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/ip.h>
    #include <netinet/tcp.h>

    #define PCKT_LEN 8192

    struct ipheader {
    unsigned char iph_ihl :5, /* Little-endian */
    iph_ver :4;
    unsigned char iph_tos;
    unsigned short int iph_len;
    unsigned short int iph_ident;
    unsigned char iph_flags;
    unsigned short int iph_offset;
    unsigned char iph_ttl;
    unsigned char iph_protocol;
    unsigned short int iph_chksum;
    unsigned int iph_sourceip;
    unsigned int iph_destip;
    };

    struct tcpheader {
    unsigned short int tcph_srcport;
    unsigned short int tcph_destport;
    unsigned int tcph_seqnum;
    unsigned int tcph_acknum;
    unsigned char tcph_reserved :4, tcph_offset :4;
    unsigned int tcp_res1 :4, /*little-endian*/
    tcph_hlen :4, /*length of tcp header in 32-bit words*/
    tcph_fin :1, /*Finish flag "fin"*/
    tcph_syn :1, /*Synchronize sequence numbers to start a connection*/
    tcph_rst :1, /*Reset flag */
    tcph_psh :1, /*Push, sends data to the application*/
    tcph_ack :1, /*acknowledge*/
    tcph_urg :1, /*urgent pointer*/
    tcph_res2 :2;
    unsigned short int tcph_win;
    unsigned short int tcph_chksum;
    unsigned short int tcph_urgptr;
    };

    unsigned short csum(unsigned short *buf, int len) {
    unsigned long sum;
    for (sum = 0; len > 0; len--){
    sum += *buf++;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return (unsigned short) (~sum);
    }

    int main(int argc, char *argv[]) {
    int sd;
    [B] // No data, just datagram
    char buffer[PCKT_LEN];[/B]
    // The size of the headers
    struct ipheader *ip = (struct ipheader *) buffer;
    struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof(struct ipheader));
    struct sockaddr_in sin, din;
    int one = 1;
    const int *val = &one;

    memset(buffer, 0, PCKT_LEN);

    if (argc != 5) {
    printf("- Invalid parameters!!!\n");
    printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
    exit(-1);
    }

    sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sd < 0) {
    perror("socket() error");
    exit(-1);
    } else {
    printf("socket()-SOCK_RAW and tcp protocol is OK.\n");
    }
    // The source is redundant, may be used later if needed
    // Address family
    sin.sin_family = AF_INET;
    din.sin_family = AF_INET;
    // Source port, can be any, modify as needed
    sin.sin_port = htons(atoi(argv[2]));
    din.sin_port = htons(atoi(argv[4]));
    // Source IP, can be any, modify as needed
    sin.sin_addr.s_addr = inet_addr(argv[1]);
    din.sin_addr.s_addr = inet_addr(argv[3]);
    // IP structure
    ip->iph_ihl = 5;
    ip->iph_ver = 4;
    ip->iph_tos = 16;
    ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
    ip->iph_ident = htons(54321);
    ip->iph_offset = 0;
    ip->iph_ttl = 64;
    ip->iph_protocol = 6; // TCP
    ip->iph_chksum = 0; // Done by kernel

    // Source IP, modify as needed, spoofed, we accept through command line argument
    ip->iph_sourceip = inet_addr(argv[1]);
    // Destination IP, modify as needed, but here we accept through command line argument
    ip->iph_destip = inet_addr(argv[3]);

    // The TCP structure. The source port, spoofed, we accept through the command line
    tcp->tcph_srcport = htons(atoi(argv[2]));
    // The destination port, we accept through command line
    tcp->tcph_destport = htons(atoi(argv[4]));
    tcp->tcph_seqnum = htonl(1);
    tcp->tcph_acknum = 0;
    tcp->tcph_offset = 5;
    tcp->tcph_syn = 1;
    tcp->tcph_ack = 0;
    tcp->tcph_win = htons(32767);
    tcp->tcph_chksum = 0; // Done by kernel
    tcp->tcph_urgptr = 0;
    // IP checksum calculation
    ip->iph_chksum = csum((unsigned short *) buffer, (sizeof(struct ipheader) + sizeof(struct tcpheader)));

    // Inform the kernel do not fill up the headers' structure, we fabricated our own
    if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
    perror("setsockopt() error");
    exit(-1);
    } else {
    printf("setsockopt() is OK\n");
    }
    printf("Using:::::Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));

    // sendto() loop, send every 2 second for 50 counts
    unsigned int count;
    for (count = 0; count < 20; count++) {
    if (sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *) &sin, sizeof(sin)) < 0){ // Verify
    perror("sendto() error");
    exit(-1);
    } else {
    printf("Count #%u - sendto() is OK\n", count);
    }
    sleep(2);
    }
    close(sd);
    return 0;
    }


    I was able to use this C code to send a MULTICAST packet that had data within it. It takes a destination IP and a destination port as the arguments. Then it asks for the message. It works as I have verified via WireShark. I want to do this but with TCP, and then with UDP.


    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #define MAX_LEN 1024

    int main(int argc, char *argv[]) {
    int sock;
    char message_to_send[MAX_LEN];
    unsigned int send_len;
    char* multicast_ip;
    unsigned short multicast_port;
    unsigned char multicast_ttl = 1;
    struct sockaddr_in multicast_addr;

    if (argc != 3) {
    fprintf(stderr, "Usage: %s Multicast_IP Multicast_Port\n", argv[0]);
    exit(1);
    }

    multicast_ip = argv[1]; /* arg 1: multicast IP address */
    multicast_port = atoi(argv[2]); /* arg 2: multicast port number */

    /* create a socket */
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    perror("Socket creation failed");
    exit(1);
    }

    /* set the TTL (time to live/hop count) for the send */
    if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (void*) &multicast_ttl, sizeof(multicast_ttl))) < 0) {
    perror("setsockopt() failed");
    exit(1);
    }

    memset(&multicast_addr, 0, sizeof(multicast_addr));
    multicast_addr.sin_family = AF_INET;
    multicast_addr.sin_addr.s_addr = inet_addr(multicast_ip);
    multicast_addr.sin_port = htons(multicast_port);

    printf("Type the message below (Press Enter to send, ctrl-C to quit):\n");

    memset(message_to_send, 0, sizeof(message_to_send));

    while (fgets(message_to_send, MAX_LEN, stdin)) {
    send_len = strlen(message_to_send);

    if ((sendto(sock, message_to_send, send_len, 0, (struct sockaddr *) &multicast_addr, sizeof(multicast_addr))) != send_len) {
    perror("Error in number of bytes");
    exit(1);
    }

    memset(message_to_send, 0, sizeof(message_to_send));
    }

    close(sock);

    exit(0);
    }


    How can I do this?
  2. #2
    aldra JIDF Controlled Opposition
    I wrote something like this a while back, was pretty similar from the look of it. I'll read over the code later tonight
  3. #3
    LiquidIce Houston
    Here's my go at it. I modified your first code with what little C I know to do these things:

    - add a field to the tcpheader struct called "tcph_msg"
    - change the stuff with argc to pass in data through the cli as the last argument
    - copy the string from argv[5] into tcph_msg
    - calculate the length of the packet and set ip->iph_len to it

    I haven't tested it but I hope it at least gives you a rough idea what's involved in adding a piece of data to the packet. The tricky part for me was understanding what lines 59 and 60 do and I think that this is what happens:
    - take a 8192 long piece of memory (which is more than enough)
    - create a pointer *ip to the start of the buffer(at position buffer[0]) that is cast as the ipheader struct.
    - create a pointer *tcp to LENGTH_OF_IP_HEADER (at position buffer[LEN_OF_IP_HEADER]) that is cast as the tcpheader struct.
    - zero the whole buffer out.


    #include <unistd.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/ip.h>
    #include <netinet/tcp.h>

    #define PCKT_LEN 8192
    #define MSG_LEN 1024

    struct ipheader {
    unsigned char iph_ihl :5, /* Little-endian */
    iph_ver :4;
    unsigned char iph_tos;
    unsigned short int iph_len;
    unsigned short int iph_ident;
    unsigned char iph_flags;
    unsigned short int iph_offset;
    unsigned char iph_ttl;
    unsigned char iph_protocol;
    unsigned short int iph_chksum;
    unsigned int iph_sourceip;
    unsigned int iph_destip;
    };

    struct tcpheader {
    unsigned short int tcph_srcport;
    unsigned short int tcph_destport;
    unsigned int tcph_seqnum;
    unsigned int tcph_acknum;
    unsigned char tcph_reserved :4, tcph_offset :4;
    unsigned int tcp_res1 :4, /*little-endian*/
    tcph_hlen :4, /*length of tcp header in 32-bit words*/
    tcph_fin :1, /*Finish flag "fin"*/
    tcph_syn :1, /*Synchronize sequence numbers to start a connection*/
    tcph_rst :1, /*Reset flag */
    tcph_psh :1, /*Push, sends data to the application*/
    tcph_ack :1, /*acknowledge*/
    tcph_urg :1, /*urgent pointer*/
    tcph_res2 :2;
    unsigned short int tcph_win;
    unsigned short int tcph_chksum;
    unsigned short int tcph_urgptr;
    char tcph_msg[MSG_LEN];
    };

    unsigned short csum(unsigned short *buf, int len) {
    unsigned long sum;
    for (sum = 0; len > 0; len--){
    sum += *buf++;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return (unsigned short) (~sum);
    }

    int main(int argc, char *argv[]) {
    int sd;
    // No data, just datagram
    char buffer[PCKT_LEN];
    // The size of the headers
    struct ipheader *ip = (struct ipheader *) buffer;
    struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof(struct ipheader));
    struct sockaddr_in sin, din;
    int one = 1;
    const int *val = &one;

    memset(buffer, 0, PCKT_LEN);

    if (argc != 6) {
    printf("- Invalid parameters!!!\n");
    printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port> <data>\n", argv[0]);
    exit(-1);
    }

    sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sd < 0) {
    perror("socket() error");
    exit(-1);
    } else {
    printf("socket()-SOCK_RAW and tcp protocol is OK.\n");
    }
    // The source is redundant, may be used later if needed
    // Address family
    sin.sin_family = AF_INET;
    din.sin_family = AF_INET;
    // Source port, can be any, modify as needed
    sin.sin_port = htons(atoi(argv[2]));
    din.sin_port = htons(atoi(argv[4]));
    // Source IP, can be any, modify as needed
    sin.sin_addr.s_addr = inet_addr(argv[1]);
    din.sin_addr.s_addr = inet_addr(argv[3]);
    // IP structure
    ip->iph_ihl = 5;
    ip->iph_ver = 4;
    ip->iph_tos = 16;
    ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
    ip->iph_ident = htons(54321);
    ip->iph_offset = 0;
    ip->iph_ttl = 64;
    ip->iph_protocol = 6; // TCP
    ip->iph_chksum = 0; // Done by kernel

    // Source IP, modify as needed, spoofed, we accept through command line argument
    ip->iph_sourceip = inet_addr(argv[1]);
    // Destination IP, modify as needed, but here we accept through command line argument
    ip->iph_destip = inet_addr(argv[3]);

    // The TCP structure. The source port, spoofed, we accept through the command line
    tcp->tcph_srcport = htons(atoi(argv[2]));
    // The destination port, we accept through command line
    tcp->tcph_destport = htons(atoi(argv[4]));
    tcp->tcph_seqnum = htonl(1);
    tcp->tcph_acknum = 0;
    tcp->tcph_offset = 5;
    tcp->tcph_syn = 1;
    tcp->tcph_ack = 0;
    tcp->tcph_win = htons(32767);
    tcp->tcph_chksum = 0; // Done by kernel
    tcp->tcph_urgptr = 0;
    strncpy(*tcp->tcph_msg, *argv[5], MSG_LEN)

    // Calculate the ip len after adding data
    ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader) + strlen(tcp->tcph_msg)
    // IP checksum calculation
    ip->iph_chksum = csum((unsigned short *) buffer, (sizeof(struct ipheader) + sizeof(struct tcpheader)));

    // Inform the kernel do not fill up the headers' structure, we fabricated our own
    if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
    perror("setsockopt() error");
    exit(-1);
    } else {
    printf("setsockopt() is OK\n");
    }
    printf("Using:::::Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));

    // sendto() loop, send every 2 second for 50 counts
    unsigned int count;
    for (count = 0; count < 20; count++) {
    if (sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *) &sin, sizeof(sin)) < 0){ // Verify
    perror("sendto() error");
    exit(-1);
    } else {
    printf("Count #%u - sendto() is OK\n", count);
    }
    sleep(2);
    }
    close(sd);
    return 0;
    }


    Here's a diff:

    < #define MSG_LEN 1024
    43d41
    < char tcph_msg[MSG_LEN];
    69c67
    < if (argc != 6) {
    ---
    > if (argc != 5) {
    71c69
    < printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port> <data>\n", argv[0]);
    ---
    > printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
    120,123d117
    < strncpy(*tcp->tcph_msg, *argv[5], MSG_LEN)
    <
    < // Calculate the ip len after adding data
    < ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader) + strlen(tcp->tcph_msg)
    149d142
    < }
    \ No newline at end of file



    Another way to add data to this whole thing would be to create a char pointer at buffer[sizeof(ipheader) sizeof(tcpheader)], then write data to it (making sure it doesn't exceed 8192 - sizeof(ipheader) - sizeof(tcpheader), then calculate and set the ip->iph_len.

    It'd be cool if someone else could confirm this as I havent touched C since 2013.
  4. #4
    SBTlauien African Astronaut
    Edit: Your code didn't seem to work for me, but I modified it just one little line and now it works.


    #include <unistd.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/ip.h>
    #include <netinet/tcp.h>
    #include <string.h>
    #include <stdlib.h>

    #define PCKT_LEN 8192
    #define MSG_LEN 64

    struct ipheader {
    unsigned char iph_ihl :5, /* Little-endian */
    iph_ver :4;
    unsigned char iph_tos;
    unsigned short int iph_len;
    unsigned short int iph_ident;
    unsigned char iph_flags;
    unsigned short int iph_offset;
    unsigned char iph_ttl;
    unsigned char iph_protocol;
    unsigned short int iph_chksum;
    unsigned int iph_sourceip;
    unsigned int iph_destip;
    };

    struct tcpheader {
    unsigned short int tcph_srcport;
    unsigned short int tcph_destport;
    unsigned int tcph_seqnum;
    unsigned int tcph_acknum;
    unsigned char tcph_reserved :4, tcph_offset :4;
    unsigned int tcp_res1 :4, /*little-endian*/
    tcph_hlen :4, /*length of tcp header in 32-bit words*/
    tcph_fin :1, /*Finish flag "fin"*/
    tcph_syn :1, /*Synchronize sequence numbers to start a connection*/
    tcph_rst :1, /*Reset flag */
    tcph_psh :1, /*Push, sends data to the application*/
    tcph_ack :1, /*acknowledge*/
    tcph_urg :1, /*urgent pointer*/
    tcph_res2 :2;
    unsigned short int tcph_win;
    unsigned short int tcph_chksum;
    unsigned short int tcph_urgptr;
    char tcph_msg[MSG_LEN];
    };

    unsigned short csum(unsigned short *buf, int len) {
    unsigned long sum;
    for (sum = 0; len > 0; len--){
    sum += *buf++;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return (unsigned short) (~sum);
    }

    int main(int argc, char *argv[]) {
    int sd;
    // No data, just datagram
    char buffer[PCKT_LEN + MSG_LEN];
    // The size of the headers
    struct ipheader *ip = (struct ipheader *) buffer;
    struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof(struct ipheader));
    struct sockaddr_in sin, din;
    int one = 1;
    const int *val = &one;

    memset(buffer, 0, PCKT_LEN + MSG_LEN);

    if (argc != 6) {
    printf("- Invalid parameters!!!\n");
    printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port> <data>\n", argv[0]);
    exit(-1);
    }

    sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sd < 0) {
    perror("socket() error");
    exit(-1);
    } else {
    printf("socket()-SOCK_RAW and tcp protocol is OK.\n");
    }
    // The source is redundant, may be used later if needed
    // Address family
    sin.sin_family = AF_INET;
    din.sin_family = AF_INET;
    // Source port, can be any, modify as needed
    sin.sin_port = htons(atoi(argv[2]));
    din.sin_port = htons(atoi(argv[4]));
    // Source IP, can be any, modify as needed
    sin.sin_addr.s_addr = inet_addr(argv[1]);
    din.sin_addr.s_addr = inet_addr(argv[3]);
    // IP structure
    ip->iph_ihl = 5;
    ip->iph_ver = 4;
    ip->iph_tos = 16;
    ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
    ip->iph_ident = htons(54321);
    ip->iph_offset = 0;
    ip->iph_ttl = 64;
    ip->iph_protocol = 6; // TCP
    ip->iph_chksum = 0; // Done by kernel

    // Source IP, modify as needed, spoofed, we accept through command line argument
    ip->iph_sourceip = inet_addr(argv[1]);
    // Destination IP, modify as needed, but here we accept through command line argument
    ip->iph_destip = inet_addr(argv[3]);

    // The TCP structure. The source port, spoofed, we accept through the command line
    tcp->tcph_srcport = htons(atoi(argv[2]));
    // The destination port, we accept through command line
    tcp->tcph_destport = htons(atoi(argv[4]));
    tcp->tcph_seqnum = htonl(1);
    tcp->tcph_acknum = 0;
    tcp->tcph_offset = 5;
    tcp->tcph_syn = 1;
    tcp->tcph_ack = 0;
    tcp->tcph_win = htons(32767);
    tcp->tcph_chksum = 0; // Done by kernel
    tcp->tcph_urgptr = 0;
    [B] strncpy(tcp->tcph_msg, argv[5], MSG_LEN);[/B]
    // IP checksum calculation
    // Calculate the ip len after adding data
    ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader) + strlen(tcp->tcph_msg);
    // IP checksum calculation
    ip->iph_chksum = csum((unsigned short *) buffer, (sizeof(struct ipheader) + sizeof(struct tcpheader)));

    // Inform the kernel do not fill up the headers' structure, we fabricated our own
    if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
    perror("setsockopt() error");
    exit(-1);
    } else {
    printf("setsockopt() is OK\n");
    }
    printf("Using:::::Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));

    // sendto() loop, send every 2 second for 50 counts
    unsigned int count;
    for (count = 0; count < 20; count++) {
    if (sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *) &sin, sizeof(sin)) < 0){ // Verify
    perror("sendto() error");
    exit(-1);
    } else {
    printf("Count #%u - sendto() is OK\n", count);
    }
    sleep(2);
    }
    close(sd);
    return 0;
    }


    Thank you.
Jump to Top