Необработанные TCP-сокеты, получающие постоянные пакеты PSH, ACK после отправки исходных данных

#c #linux #sockets #tcp #raw-sockets

#c #linux #сокеты #tcp #необработанные сокеты

Вопрос:

В настоящее время я пытаюсь создать echo-клиент Linux, используя только необработанные сокеты. Я использую обычный TCP-сервер на одном компьютере, а на стороне клиента я использую необработанные TCP-сокеты. Я запускаю Libpcap на своей стороне клиента для приема пакетов и ответа при получении пакетов. У меня завершено трехстороннее подтверждение связи и установлено соединение между клиентом и сервером.

Я могу отправить свой первый запрос подтверждения и PSH, ACK (пакеты 3 и 4) с данными и получить ответ от сервера с данными, которые я первоначально отправил (пакеты 5 и 6).

Есть идеи, как остановить отправку PSH, ACK? Я пробовал отправлять ACK, но он все еще не прекращал отправку. Ниже приведен снимок wireshark и часть кода, с которым я работаю.

Это скриншот пакетов на сервере wireshark (192.168.1.81) и клиенте (192.168.1.85): Перехват Wireshark

Клиентская необработанная TCP-оболочка

 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(amp;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: %sn", src_ip);
  printf("dst_ip: %sn", dst_ip);
  // Source IPv4 address (32 bits)
  if ((status = inet_pton(AF_INET, src_ip, amp;(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, amp;(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 *)amp;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(amp;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, amp;on, sizeof(on)) <     0) {
    perror("setsockopt() failed to set IP_HDRINCL ");
    exit(EXIT_FAILURE);
  }

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

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

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

Серверный код

 #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, amp;hints, amp;servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %sn", 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, amp;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 *)amp;their_addr, amp;sin_size);
if (new_fd == -1) {
    perror("accept");
}

inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)amp;their_addr), s, sizeof s);
printf("server: got connection from %sn", 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 %sn",data, s);
    send_normal_tcp_packet(new_fd, data, bytes_receieved);
}
close(new_fd);
close(sockfd);

return 0;
}
  

Ответ №1:

Ваш клиент неправильно подтверждает полученные данные (с сервера).

Теперь похоже, что пакет # 6 содержит данные с сервера. Пакет # 7 повторно передается через 200 мс, потому что клиент не подтвердил достаточно быстро. Это небольшая проблема.

Основная проблема заключается в пакете # 8: клиент пытается подтвердить порядковый номер 321910546. Поэтому сервер, вероятно, игнорирует это. В этом случае правильное число должно быть 6 (seq 1 len 5).

Таким образом, сервер пытается повторно передать эхо-сигналы несколько раз, потому что он не получает действительного подтверждения.

Комментарии:

1. Я пытался отправить пакет подтверждения с номером подтверждения 6 и порядковым номером 6, но всякий раз, когда сервер получает мой пакет, он становится очень большим числом, таким как пакет в пакете # 8. Я заметил это при работе над трехсторонним рукопожатием, но не был уверен, почему это происходит. Это случается только изредка

2. Эта строка выглядит нормально: «packet.tcphdr.th_ack = htonl(ack);» Так что, возможно, значение переменной ack все еще неверно, или кто-то перезаписывает его.

3. Мне просто нужно было поменять номер SEQ на номер ACK, и это исправило ситуацию.