Search code examples
csocketstcp

RST not sent or received in C with socket


I am trying to receive the RST packets sent to my program after I send several SYN packet to a closed port, the case is I am seeing any RST segments being sent or received, as I confirmed this through Wireshark. Here is the SYN segment configuration:

    char packet[BUF_SIZE];
    struct iphdr* ip_h = (struct iphdr*) packet;
    struct tcphdr* tcp_h = (struct tcphdr*) (packet + sizeof(struct iphdr));
    struct pseudo_header ps_h;

    ip_h->ihl = 5;
    ip_h->version = 4;
    ip_h->tos = 0;
    ip_h->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr);
    ip_h->id = htons(54321);
    ip_h->frag_off = 0;
    ip_h->ttl = 255;
    ip_h->protocol = IPPROTO_TCP;
    ip_h->check = 0;
    ip_h->saddr = inet_addr(cf->src_ip);
    ip_h->daddr = inet_addr(cf->server_ip);

    tcp_h->source = htons(12345);
    tcp_h->dest = htons(dest_port);
    tcp_h->seq = 0;
    tcp_h->ack_seq = 0;
    tcp_h->doff = 5;
    tcp_h->fin = 0;
    tcp_h->syn = 1;
    tcp_h->rst = 0;
    tcp_h->psh = 0;
    tcp_h->ack = 0;
    tcp_h->urg = 0;
    tcp_h->check = 0;
    tcp_h->window = htons (5840);
    tcp_h->urg_ptr = 0;

    memset(&ps_h, 0, sizeof(ps_h));
    ps_h.source_address = inet_addr("192.168.128.2");
    ps_h.dest_address = inet_addr(cf->server_ip);
    ps_h.placeholder = 0;
    ps_h.protocol = IPPROTO_TCP;
    ps_h.tcp_length = htons(sizeof(struct tcphdr));

    int pseudo_size = sizeof(struct pseudo_header) + sizeof(struct tcphdr);
    char *pseudo_packet = malloc(pseudo_size);
    memcpy(pseudo_packet, (char *) &ps_h, sizeof(struct pseudo_header));
    memcpy(pseudo_packet + sizeof(struct pseudo_header), tcp_h, sizeof(struct tcphdr));

    tcp_h->check = checksum(pseudo_packet, pseudo_size);
    ip_h->check = checksum(packet, ip_h->tot_len);

pseudo_header

struct pseudo_header {
    u_int32_t source_address;
    u_int32_t dest_address;
    u_int8_t placeholder;
    u_int8_t protocol;
    u_int16_t tcp_length;
};

Checksum algorithm:

unsigned short checksum(const char *buf, unsigned size) {
    unsigned sum = 0, i;
    /* Accumulate checksum */
    for (i = 0; i < size - 1; i += 2) {
        unsigned short word16 = *(unsigned short *) &buf[i];
        sum += word16;
    }
    /* Handle odd-sized case */
    if (size & 1) {
        unsigned short word16 = (unsigned char) buf[i];
        sum += word16;
    }
    /* Fold to get the ones-complement result */
    while (sum >> 16) sum = (sum & 0xFFFF)+(sum >> 16);
    /* Invert to get the negative in ones-complement arithmetic */
    return ~sum;
}

Screenshot For SYN Segment

In addition, when I check the SYN segment through Wireshark, this kinda looks off to me, as ECN and CWR aren't supposed to be set, including Reserved as well, but I don't think I will be able to manually set them off in the program.

For now, I could only think of two issues, it is either my SYN segment is not correctly setup, but it looks good to me. Or the server simply does not send RST, for this, I tried with nc -l -p 9999(destination port where SYN is sent to) to open up this port on server end, hoping it to send SYN-ACK, but still no response.


Solution

  • I somehow addressed where the issue was, that my ip and tcp header lengths are not calculated correctly, given by this project, there should be an OPT_SIZE in addition to the length.