0
votes

I'm currently trying to create a Linux echo client using only raw sockets. I'm running a normal TCP server on one computer, and on the client side i'm using raw TCP sockets. I'm running Libpcap on my client side to receive packets and reply when packets are received. I have the three way handshake complete and have a established connection between the client and server.

I am able to send my first ACK, and PSH,ACK(packets 3 & 4) with data and receive a reply from the server with the data that I originally sent(packets 5 & 6).

Any ideas how to stop the PSH, ACKs from sending? I've tried sending an ACK but it would not stop sending still. Below is a wireshark capture and some of the code i'm working with.

This is a screenshot of the packets on wireshark Server(192.168.1.81) Client(192.168.1.85): Wireshark capture

Client Raw TCP Wrapper

void send_raw_tcp_packet(int src_port, int dst_port, struct ifreq interface, 
char* src_ip, char* dst_ip, int seq, int ack, char *data, int flags) {
  struct sockaddr_in sin;
  int *ip_flags, *tcp_flags, status, sending_socket;
  const int on = 1;
  struct tcp_packet packet;
  ip_flags = (int *)calloc(4, sizeof(int));
  tcp_flags = (int *)calloc(8, sizeof(int));
  int payloadlen = 0;
  memset(&packet, 0, sizeof(struct tcp_packet));

  // IPv4 header
  packet.iphdr.ip_hl = IP4_HDRLEN / sizeof(uint32_t); //header length = 5
  packet.iphdr.ip_v = 4; //version = 4
  packet.iphdr.ip_tos = 0; //TOS
  packet.iphdr.ip_len = htons(IP4_HDRLEN + TCP_HDRLEN); //length: IP header     + TCP header
  packet.iphdr.ip_id = htons(0); //ID
  ip_flags[0] = 0; //Zero
  ip_flags[1] = 0; //Don't frag
  ip_flags[2] = 0; //More frag
  ip_flags[3] = 0; //Frag offset
  packet.iphdr.ip_off = htons((ip_flags[0] << 15) + (ip_flags[1] << 14) +    (ip_flags[2] << 13) + ip_flags[3]);
  packet.iphdr.ip_ttl = 255; //TTL
  packet.iphdr.ip_p = IPPROTO_TCP; //Protocol
  printf("src_ip: %s\n", src_ip);
  printf("dst_ip: %s\n", dst_ip);
  // Source IPv4 address (32 bits)
  if ((status = inet_pton(AF_INET, src_ip, &(packet.iphdr.ip_src))) != 1) {
     perror("inet_pton, src_ip");
  exit(EXIT_FAILURE);
  }
  // Destination IPv4 address (32 bits)
  if ((status = inet_pton(AF_INET, dst_ip, &(packet.iphdr.ip_dst))) != 1) {
      perror("inet_pton, dst_ip");
    exit(EXIT_FAILURE);
  }

  packet.iphdr.ip_sum = 1;
  packet.iphdr.ip_sum = checksum((uint16_t *)&packet.iphdr, IP4_HDRLEN);

  // TCP header
  if (src_port == 0) {
    packet.tcphdr.th_sport = generate_rand(65535.0);
  } else {
    packet.tcphdr.th_sport = src_port;
  }
  if (dst_port == 0) {
    packet.tcphdr.th_dport = generate_rand(65535.0);
  } else {
    packet.tcphdr.th_dport = htons(dst_port);
  }
  packet.tcphdr.th_seq = htonl(seq); //SEQ
  packet.tcphdr.th_ack = htonl(ack); //ACK - 0 for first packet
  packet.tcphdr.th_x2 = 0; //Reserved
  packet.tcphdr.th_off = TCP_HDRLEN / 4; //Offset

  // Flags (8 bits)
  if(flags == PSHACK){
    tcp_flags[0] = 0; //FIN
    tcp_flags[1] = 0; //SYN
    tcp_flags[3] = 1; //PSH
    tcp_flags[4] = 1; //ACK
    tcp_flags[2] = 0; //RST
  }else if(flags == SYNACK){
    tcp_flags[0] = 0; //FIN
    tcp_flags[1] = 1; //SYN
    tcp_flags[3] = 0; //PSH
    tcp_flags[4] = 1; //ACK
    tcp_flags[2] = 0; //RST
  }else if(flags == FINACK){
    tcp_flags[0] = 1; //FIN
    tcp_flags[1] = 0; //SYN
    tcp_flags[3] = 0; //PSH
    tcp_flags[4] = 1; //ACK
    tcp_flags[2] = 0; //RST
  }else if(flags == FIN){
    tcp_flags[0] = 1; //FIN
    tcp_flags[1] = 0; //SYN
    tcp_flags[3] = 0; //PSH
    tcp_flags[4] = 0; //ACK
    tcp_flags[2] = 0; //RST
  } else if(flags == SYN){
    tcp_flags[0] = 0; //FIN
    tcp_flags[1] = 1; //SYN
    tcp_flags[3] = 0; //PSH
    tcp_flags[4] = 0; //ACK
    tcp_flags[2] = 0; //RST
  }else if(flags == ACK){
    tcp_flags[0] = 0; //FIN
    tcp_flags[1] = 0; //SYN
    tcp_flags[3] = 0; //PSH
    tcp_flags[4] = 1; //ACK
    tcp_flags[2] = 0; //RST
  }else if(flags == RST){
    tcp_flags[0] = 0; //FIN
    tcp_flags[1] = 0; //SYN
    tcp_flags[3] = 0; //PSH
    tcp_flags[4] = 0; //ACK
    tcp_flags[2] = 1; //RST
  }
  tcp_flags[5] = 0; //URG
  tcp_flags[6] = 0; //ECE
  tcp_flags[7] = 0; //CWR
  packet.tcphdr.th_flags = 0;
  for (int i = 0; i < 8; i++) {
    packet.tcphdr.th_flags += (tcp_flags[i] << i);
  }

  packet.tcphdr.th_win = htons(64240); //Window size
  packet.tcphdr.th_urp = htons(0); //Urgent Pointer
  //memset(packet.payload, 0, sizeof(packet.payload));
  if(data != NULL){
    sprintf (packet.payload, "%s", data);
    payloadlen = strlen(packet.payload);
  }
  //payloadlen = strlen(packet.payload);
  packet.tcphdr.th_sum = tcp4_checksum(packet.iphdr, packet.tcphdr, (uint8_t     *) packet.payload, payloadlen);

  memset(&sin, 0, sizeof(struct sockaddr_in));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = packet.iphdr.ip_dst.s_addr;

  if ((sending_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
    perror("socket() failed ");
    exit(EXIT_FAILURE);
  }

  if (setsockopt(sending_socket, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) <     0) {
    perror("setsockopt() failed to set IP_HDRINCL ");
    exit(EXIT_FAILURE);
  }

  if (setsockopt(sending_socket, SOL_SOCKET, SO_BINDTODEVICE,     &interface,sizeof(interface)) < 0) {
    perror("setsockopt() failed to bind to interface ");
    exit(EXIT_FAILURE);
  }

  if (sendto(sending_socket, &packet, IP4_HDRLEN + TCP_HDRLEN + payloadlen,     0, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
    perror("sendto() failed ");
    exit(EXIT_FAILURE);
  }

  close(sending_socket);
  // Free allocated memory.
  free(ip_flags);
  free(tcp_flags);
}

Server code

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

#define PORT "8045"
#define MAXCONNECTIONS 1024


int main(void){
    int sockfd, new_fd,rv, yes =1;
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_storage their_addr;
    socklen_t sin_size;
    struct sigaction sa;
    char s[INET6_ADDRSTRLEN];


    hints = set_hints(AF_UNSPEC, SOCK_STREAM, AI_PASSIVE);

    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return 1;
}

for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,p->ai_protocol)) == -1) {
        perror("server: socket");
        continue;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
            sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("server: bind");
        continue;
    }

    break;
}

freeaddrinfo(servinfo);

if (listen(sockfd, MAXCONNECTIONS) == -1) {
    perror("listen");
    exit(1);
}

printf("server: waiting for connections...\n");
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
    perror("accept");
}

inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server: got connection from %s\n", s);
while(1) {
    char data[1024];
    //recv_normal_tcp_packet(new_fd, data, sizeof(data));
    int bytes_receieved = recv(new_fd, data, sizeof(data),0);
    printf("Received: %s from %s\n",data, s);
    send_normal_tcp_packet(new_fd, data, bytes_receieved);
}
close(new_fd);
close(sockfd);

return 0;
}
1

1 Answers

0
votes

Your client does not acknowledge the received data (from server) correctly.

Now it looks like that packet #6 contains data from the server. Packet #7 is re-transmission after 200ms, because the client didn't acknowledge fast enough. That is minor problem.

The main problem is in packet #8: The client tries to acknowledge sequence number 321910546. So server probably ignores that. In this case correct number should be 6 (seq 1 + len 5).

So the server try to re-transmit the echo(s) several times, because it does not receive valid acknowledge.