Почему мой пример кода не получает ACK от SYN?Linux

Ответить
Anonymous
 Почему мой пример кода не получает ACK от SYN?

Сообщение Anonymous »

Я пытаюсь проверить поведение тестируемого устройства на соответствие RFC5961. Для проверки необходимо внедрить пакет RST с порядковым номером в окне, а не с ожидаемым номером. Итак, я использую машину с Linux Ubuntu 18 для создания пакетов.
Первый шаг — установить соединение. И это не работает. Пример, который я нашел, закрывает сокет, и код, который я пытаюсь переписать, никогда не получает подтверждения от DUT. Как только я это преодолею, все станет легко.
Изначально я использовал эти примеры https://pdbuchan.com/rawsock/rawsock.html
, которые показывают, как создавать необработанный (TCP) пакет для отправки SYN и получения ACK.
Пакет 1 и 2 и все идеально. Но пакет 3 не генерируется кодом.
Проблема в том, что после подтверждения SYN Linux отправляет RST самостоятельно. Я узнал, что это потому, что в сокете ничего не прослушивается и не подключается. Я не знаю, как это обойти, так как он закрывается еще до того, как мой тест успевает выдать "revcfrom()"
Изображение

Когда я попытался внести какие-либо изменения в код для его настройки, DUT не даже не отвечаю АКК. Несмотря на то, что пакеты по сути идентичны.
Я сверился с ними, однако они не дали ответа.
Отправка Raw Ethernet-пакета, содержащего IPv4 и TCP SYN но не получил пакет SYN/ACK в ответном пакете
НАЧАЛ получать пакет RST из клиентского сокета после того, как я ответил на пакет SYN пакетом SYN + ACK
A несколько лет назад я создал Модификация 802.1x Wired, создающая пакеты Ethernet типа 0x888e. Все это работало, когда пакет был полностью сырым и создавался с нуля. Поэтому я подумал: «Почему бы просто не создать пакет самому?»
Тем не менее, DUT не отвечает ACK или чем-то еще.
Моя установка — это Linux Ubuntu 18 и тестируемое устройство на том же NetGear «Prosafe JGS524E». IP-адреса им назначил маршрутизатор ATT. Исторически сложилось так, что я мог создавать необработанные пакеты и отправлять их на тестируемое устройство.
Оба теста всего кода, предназначенного только для тестирования тестируемого устройства, имеют жестко закодированные значения. Здесь показаны два примера. И снимки экрана WireShark, показывающие пакеты, включены.
Вопрос: почему пакет из второго кода не получает ответа?
Весь Код Бьюкена, который отправляет SYN и получает ACK, а затем Linux отправляет RST, находится здесь:

Код: Выделить всё

{   Code exceeded the limit of an allowed post...  see Buchan's example here:
https://pdbuchan.com/rawsock/tcp4.c
Вот мой код (созданный на основе кода RAW Ethernet, который создает 802.1 X-пакеты и работает для 802.1X). Когда я создаю пакет, который практически идентичен приведенному выше коду, DUT даже не отвечает. Я перепробовал так много вариантов, что их публикация не стоит дополнительной пропускной способности. Ничего не работает.
Анализ Wireshark не выявил никаких проблем с пакетом. Просто одинокий пакет на один и тот же MAC/IP, на который DUT не отвечает.
[img]https:// i.sstatic.net/LF3z8Kdr.jpg[/img]

Код разбит на «основной» и «пакетный» класс. Большая часть взята из приведенного выше примера
Main.cpp:

Код: Выделить всё

#include 
#include 
#include 
#include 
#include 

#include 
#include        // struct ip and IP_MAXPACKET (which is 65535)
#include        // IPPROTO_RAW, IPPROTO_IP, IPPROTO_TCP, INET_ADDRSTRLEN
#define __FAVOR_BSD           // Use BSD format of tcp header
#include       // struct tcphdr
#include         // inet_pton() and inet_ntop()

#include 
#include "Packet.h"

int BuildEthernetHdr(unsigned char *buffer, uint8_t *src_ip, uint8_t *dst_ip);
int BuildIPHdr(unsigned char *buffer, const char *src_ip, const char *dst_ip);
int BuildTCPHdr(unsigned char *buffer);

uint16_t checksum (uint8_t *addr, int len);

unsigned char buffer[2048];
int main() {
int len;
unsigned char *pkt;
CPacket packet;

uint8_t     srcMac[6];
uint8_t     dstMac[6];

memcpy(srcMac, "\x60\xa4\x4c\x63\x4d\x9e", 6);
memcpy(dstMac, "\xa4\x9b\x13\x00\xfe\x0e", 6);

packet.SetInterface("SetInterface");
packet.Initialize();
pkt = buffer;
len = BuildEthernetHdr(pkt,srcMac, dstMac);
pkt += len;

len = BuildIPHdr(pkt, "192.168.1.211","192.168.1.94");
pkt += len;

len = BuildTCPHdr(pkt);
pkt += len;

puts("---  IP HEADER ---");
for (int i = 0; i < pkt - buffer; i++) {
printf("%02x ", buffer[i]);
if ((i& 0x0f) == 0x0f) puts("");
}
puts("");
len = pkt - buffer;

packet.SendMessage(buffer, len);

packet.Cleanup();
return EXIT_SUCCESS;
}

#define IP4_HDRLEN      20
#define TCP_HDRLEN      20
#define ETH_HDRLEN      14

int BuildEthernetHdr(unsigned char *buffer, uint8_t *src_mac, uint8_t *dst_mac) {
ETHERHDR * ethhdr;
ethhdr = (ETHERHDR * )buffer;

memcpy(ethhdr->srcMac, src_mac,6);
memcpy(ethhdr->dstMac, dst_mac,6);
ethhdr->etherType = htons(0x0800);

return sizeof(ETHERHDR);
}

int BuildIPHdr(unsigned char *buffer, const char *src_ip, const char *dst_ip) {
struct ip *iphdr;
int status;
unsigned int ip_flags[4];
iphdr = (struct ip*) buffer;

iphdr->ip_hl = IP4_HDRLEN / sizeof (uint32_t);

// Internet Protocol version (4 bits): IPv4
iphdr->ip_v = 4;

// Type of service (8 bits)
iphdr->ip_tos = 0;

// Total length of datagram (16 bits): IP header + TCP header
iphdr->ip_len = htons (IP4_HDRLEN + TCP_HDRLEN);

// ID sequence number (16 bits): unused, since single datagram
iphdr->ip_id = htons (0);

// Flags, and Fragmentation offset (3, 13 bits): 0 since single datagram

// Zero (1 bit)
ip_flags[0] = 0;

// Do not fragment flag (1 bit)
ip_flags[1] = 1;

// More fragments following flag (1 bit)
ip_flags[2] = 0;

// Fragmentation offset (13 bits)
ip_flags[3] = 0;

iphdr->ip_off = htons ((ip_flags[0] ip_src))) != 1) {
fprintf (stderr, "inet_pton() failed for source address.\nError message: %s", strerror (status));
exit (EXIT_FAILURE);
}

// Destination IPv4 address (32 bits)
if ((status = inet_pton (AF_INET, dst_ip, &(iphdr->ip_dst))) != 1) {
fprintf (stderr, "inet_pton() failed for destination address.\nError message: %s", strerror (status));
exit (EXIT_FAILURE);
}

// IPv4 header checksum (16 bits): set to 0 when calculating checksum
iphdr->ip_sum = 0;
iphdr->ip_sum = checksum (buffer, IP4_HDRLEN);

return sizeof(struct ip);
}

int BuildTCPHdr(unsigned char *buffer) {

struct tcphdr *tcphdr;
int optsize = 0;
unsigned int tcp_flags[8];
unsigned char optbuffer[20];

tcphdr = (struct tcphdr *) buffer;
if (false) {
//  Option     length (with itself)          value
optbuffer[0] = 2; optbuffer[1] = 4; optbuffer[2] = 5; optbuffer [3] = 0xb4;   //Max Seg Size
optbuffer[4] = 4; optbuffer[5] = 2;      // SACK permitted
uint32_t time1 = 0x12345678;  uint32_t time2 = 0x87654321;
optbuffer[6] = 8; optbuffer[7] = 10;  memcpy(&optbuffer[8], &time1, 4); memcpy(&optbuffer[12], &time2, 4);
optbuffer[16] = 1; // NoOp
optbuffer[17] = 3; optbuffer[18] = 3; optbuffer[19] = 7;     // Shift Multiplier
optsize = 20;
}
// Source port number (16 bits)
tcphdr->th_sport = htons (8080);

// Destination port number (16 bits)
tcphdr->th_dport = htons (80);

// Sequence number (32 bits)
tcphdr->th_seq = htonl (5);

// Acknowledgement number (32 bits): 0 in first packet of SYN/ACK process
tcphdr->th_ack = htonl (0);

// Reserved (4 bits): should be 0
tcphdr->th_x2 = 0;

// Data offset (4 bits): size of TCP header in 32-bit words
tcphdr->th_off = (TCP_HDRLEN + optsize) / 4;

// Flags (8 bits)

// FIN flag (1 bit)
tcp_flags[0] = 0;

// SYN flag (1 bit): set to 1
tcp_flags[1] = 1;

// RST flag (1 bit)
tcp_flags[2] = 0;

// PSH flag (1 bit)
tcp_flags[3] = 0;

// ACK flag (1 bit)
tcp_flags[4] = 0;

// URG flag (1 bit)
tcp_flags[5] = 0;

// ECE flag (1 bit)
tcp_flags[6] = 0;

// CWR flag (1 bit)
tcp_flags[7] = 0;

tcphdr->th_flags = 0;
for (int i=0; ith_flags += (tcp_flags[i] th_win = htons (8192);

// Urgent pointer (16 bits): 0 (only valid if URG flag is set)
tcphdr->th_urp = htons (0);

// TCP checksum (16 bits)
tcphdr->th_sum = checksum (buffer, sizeof(struct tcphdr));

return sizeof(struct tcphdr);

}

// Computing the internet checksum (RFC 1071).
// Note that the internet checksum is not guaranteed to preclude collisions.
uint16_t checksum (uint8_t *addr, int len) {

int count = len;
register uint32_t sum = 0;
uint16_t answer = 0;

// Sum up 2-byte values until none or only one byte left.
while (count > 0) {
sum += *(addr++);
count -= 1;
}

// Fold 32-bit sum into 16 bits; we lose information by doing this,
// increasing the chances of a collision.
// sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
while (sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}

// Checksum is one's compliment of sum.
answer = ~sum;

return (answer);
}
Packet.cpp (большая часть моего программирования на C++ заключается в обертывании кода C для инкапсуляции, чтобы затруднить работу разработчика C)

Код: Выделить всё

#include 
#include 
#include 
#include 
#include 

#include 
#include        // struct ip and IP_MAXPACKET (which is 65535)
#define __FAVOR_BSD           // Use BSD format of tcp header
#include        // struct tcphdr

//#include 
#include 
//#include 

//#include 
//#include 
//#include 

//#include 

#include 
#include "Packet.h"
//   Source (me) is 60:a4:4c:63:4d:9e
//   DUT is     a4:9b:13:00:fe:0e
CPacket::CPacket() {
m_socket = -1;

}
CPacket::~CPacket() {
Cleanup();
}

void CPacket::Cleanup() {

}

void CPacket::SetInterface(const char * iface) {
strcpy(m_interface, iface);
}

bool CPacket::Initialize() {
int result;
Cleanup();
// open a socket
m_socket = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);

if (m_socket == -1) {
result = errno;
puts("Failed to create raw socket");
puts(strerror(result));
return false;
}
// Get the interface
memset(&m_if_idx,0,sizeof(struct ifreq));
strcpy(m_if_idx.ifr_name,"enp3s0");
result = ioctl(m_socket, SIOCGIFINDEX,  &m_if_idx);
if (result == -1) {
result = errno;
puts("Failed to get IF info");
puts(strerror(result));
return false;
}

memset(&m_if_mac,0,sizeof(struct ifreq));

strcpy((char *) m_if_mac.ifr_name,"enp3s0");
result = ioctl(m_socket, SIOCGIFHWADDR,  &m_if_mac);
if (result == -1) {
result = errno;
puts("Failed to get MAC info");
puts(strerror(result));
return false;
}

m_socket_address.sll_family = AF_PACKET;
m_socket_address.sll_ifindex = m_if_idx.ifr_ifindex;
m_socket_address.sll_protocol = htons(0x0008);

result = bind(m_socket, (struct sockaddr*)&m_socket_address,sizeof(m_socket_address));
if (result == -1) {
result = errno;
puts("Failed to BIND");
puts(strerror(result));
return false;
}

//  Configure the socket address struct we will use to send
memset(&m_socket_address,0,sizeof(struct sockaddr_ll));
//  The MAc appears to be ignored.   So can be left as all nulls
m_socket_address.sll_ifindex = m_if_idx.ifr_ifru.ifru_ivalue;
m_socket_address.sll_halen = 6;

return true;
}

bool CPacket::SendMessage(unsigned char *msg, uint16_t len) {
int result;

#ifdef PACKET_DUMP
puts("---- PACKET DUMP TX----");
for (int x = 0; x < len; x++) {
printf("%02x ", m_buffer[x]);
if ((x & 0x0f) == 0x0f) puts("");
}
puts("\n------------");
#endif
//  And fire away
result = sendto(m_socket, msg,len,0, (struct sockaddr*) &m_socket_address, sizeof(struct sockaddr_ll));
if (result != len) {
result = errno;
puts("Failed to send");
puts(strerror(result));
return false;
}

return true;
}

uint8_t CPacket::ReceiveMessage(uint32_t delay, unsigned char *msg) {
int result;
unsigned int size;
uint32_t usec, sec;
ETHERHDR * etherhdr;
etherhdr = (ETHERHDR *) msg;
fd_set rxset;
struct timeval timeout;

delay *= 1000;      // Milli to micro...

sec = delay / 1000000;
usec = delay % 1000000;
//printf ("  delay for %d sec, %d usec\n", sec, usec);

timeout.tv_sec = sec;
timeout.tv_usec = usec;

FD_ZERO(&rxset);
FD_SET(m_socket,&rxset);

result = select(m_socket + 1,&rxset,NULL,NULL,&timeout);
if (result == 0 ) {
puts("Recv timeout");
return 0;
}

size = sizeof(m_socket_address);
do {
//  And read away
result = recvfrom(m_socket, msg,1100,0, (struct sockaddr*) &m_socket_address, &size);
if (result == -1) {
result = errno;
puts("Failed to receive...");
puts(strerror(result));
return 0;
}
#ifdef PACKET_DUMP
printf("---- PACKET DUMP RX---- %d bytes\n", result);
for (int x = 0; x < result; x++) {
printf("%02x ", m_buffer[x]);
if ((x & 0x0f) == 0x0f) puts("");
}
puts("\n------------");
#endif
if (memcmp(etherhdr->srcMac,m_if_mac.ifr_ifru.ifru_hwaddr.sa_data,6) == 0) {
//puts(" Packet from me...");
} else {
break;
}
} while (1);

return (uint8_t ) result;
}
И заголовок класса Packet.h

Код: Выделить всё

/*
* Comm.h
*
*  Created on: Apr 21, 2022
*      Author: scott
*/
#pragma once
//  Headers neded that defined the IF structs
#include 
#include 

typedef struct etherhdr {
uint8_t     dstMac[6];
uint8_t     srcMac[6];
uint16_t    etherType;      //0x0008
} ETHERHDR;

class CPacket {
public:
CPacket();
~CPacket();
void SetInterface(const char * iface);
bool Initialize();

bool SendMessage(unsigned char * msg, uint16_t len);
uint8_t ReceiveMessage(uint32_t delay, unsigned char *msg);
void Cleanup();

private:

int         m_socket;
char        m_interface[32];

struct ifreq m_if_idx;
struct ifreq m_if_mac;

struct sockaddr_ll m_socket_address;

};
Я также решил понюхать еще кое-что. Я прослушал пакет из браузера и увидел наличие параметров TCP, поэтому я создаю пакет для дополнительной поддержки (очевидно в коде, хотя отключено в вставленной мной версии)
Вот запрос браузера. Нет ничего удивительного в том, что любой, у кого есть Ethernet более низкого уровня, не знал бы):
[img]https: //i.sstatic.net/9QJeJQcK.jpg[/img]

Вот запрос, в котором я добавил опцию, но он все еще не получил подтверждения от DUT.
Изображение

Как только я решу эту проблему, я смогу изготовить пакет данных и внедрить пакет RST для проверки моей реализации соответствия RFC5961 в тестируемом устройстве.
Примечание: тестируемое устройство использует маленькое окно и недолговечные сокеты, поэтому проблема спорна, поскольку DUT на самом деле не уязвим для атаки DOS. Но попробуйте убедить в этом клиента, когда он потратил непомерную сумму денег на тестовое приложение, а оно просто ошибочно сообщает, что это открытая атака.

Подробнее здесь: https://stackoverflow.com/questions/792 ... from-a-syn
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Linux»