简体   繁体   中英

How can I send received packet using raw sockets in C?

I've wrote some code, which is not working. I need to send incoming packets to another host(2.2.2.1). This code receiving packet but can't send it. What I'm doing wrong? I'm receiving packet, than copy packet to another array and than trying to send it using sendto() function.

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

#define PCKT_LEN 8192

int main(){
    int s, s1;
    char buffer[PCKT_LEN];
    struct sockaddr saddr;
    struct sockaddr_in daddr;
    memset(buffer, 0, PCKT_LEN);

    s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if(s < 0){
        printf("socket() error");
        return -1;
    }
    int one = 1;
    const int *val = &one;
    if(setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof(one))<0){
        printf("setsock");
        return -1;
    }
    s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if(s1 < 0){
        printf("sock2 error");
        return -1;
    }
    if(setsockopt (s1, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0){
        printf("setsock");
        return -1;
    }
    int saddr_size = sizeof(saddr);
    int daddr_size = sizeof(daddr); 
    int header_size = sizeof(struct iphdr) + sizeof(struct tcphdr);
    unsigned int count;

    daddr.sin_family = AF_INET;
    daddr.sin_port = htons(1234);
    daddr.sin_addr.s_addr = inet_addr ("2.2.2.1");

    char *datagram, *data;
    datagram = (char*)calloc(4096, sizeof(char));
    struct iphdr *iph;
    struct tcphdr *tcph;
    int counter = 0;
    while(counter != 3){
        counter++;
        if(recvfrom(s, buffer, PCKT_LEN , 0, &saddr, &saddr_size) < 0){
            printf("recvfrom() error");
            return -1;
        }
        else{
            int i = header_size;
            int packet_len = ntohs(iph->tot_len);           
            memset(datagram, 0 ,4096);
            iph = (struct iphdr*) buffer;
            tcph = (struct tcphdr*) (buffer + sizeof(struct ip));
            data = buffer + sizeof(struct iphdr) + sizeof(struct tcphdr);

            i = 0;
            for(; i < packet_len-sizeof(struct iphdr)-sizeof(struct tcphdr); i++)
                printf("%c", data[i]);
                 printf("\n");

            memcpy(datagram, iph, sizeof(struct iphdr));
            memcpy(datagram+sizeof(struct iphdr), tcph , sizeof(struct tcphdr));
            memcpy(datagram+sizeof(struct iphdr)+sizeof(struct tcphdr), data,packet_len-sizeof(struct iphdr)-sizeof(struct tcphdr));

            iph->daddr = daddr.sin_addr.s_addr;

            if (sendto (s, datagram, packet_len, 0, &daddr, &daddr_size) < 0){
                printf("sendto() error");
                return -1;
            }
        }
    }
    close(s);
    close(s1);
    free(datagram);
    return 0;
}
  1. You didn't include stdlib.h and hence calloc() is implicitly declared so the compiler assumes it returns int , and that will cause many problems.

    Also, don't use calloc() unless you really want to initialize data to 0 's, because if you have a problem with data initialization, then nothing bad will happen, and you will never know. Use malloc() unless you are going to memset(pointer, 0, size); later, which isn't bad either, in my case, I always use malloc() .

  2. You didn't include unistd.h either so you have a missing declaration for close() too. This one is not causing problems, but just because conicidentially it returns int .

  3. Your sendto() call is also wrong, the last argument should be of type socklen_t and you passed a int * , so fix it like this

     sendto (s, datagram, packet_len, 0, (struct sockaddr *)&daddr, daddr_size) < 0 /* ^ no & here */ 
  4. To avoid some of the warnings that will appear when you ask the compiler to warn you you will need to declare these to variables as socklen_t

     socklen_t saddr_size = sizeof(saddr); socklen_t daddr_size = sizeof(daddr); 

    and also you need the cast that you see above (struct sockaddr *)&daddr .

  5. The most important problem is that you try to access iph without initializing it

     size_t packet_len = ntohs(iph->tot_len); 

    this should go after iph = (struct iphdr *)buffer; .

    The cause for this, is precisely that your code is so messy that it's hard to notice that.

You can avoid all this by using compiler warnings, like this

gcc -Wall -Wextra -Werror sourcefile.c -o executable

Note : organize your code better, it's very hard to follow, and that's not good if someone else has to review it, like I did just now, also for you it's not good, because when you look at it months from now, you will be very angry at the person who wrote that mess.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM