Первый шаг — установить соединение. И это не работает. Пример, который я нашел, закрывает сокет, и код, который я пытаюсь переписать, никогда не получает подтверждения от 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:
Вот мой код (созданный на основе кода 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);
}
Код: Выделить всё
#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;
}
Код: Выделить всё
/*
* 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;
};
Вот запрос браузера. Нет ничего удивительного в том, что любой, у кого есть Ethernet более низкого уровня, не знал бы):
[img]https: //i.sstatic.net/9QJeJQcK.jpg[/img]
Вот запрос, в котором я добавил опцию, но он все еще не получил подтверждения от DUT.

Как только я решу эту проблему, я смогу изготовить пакет данных и внедрить пакет RST для проверки моей реализации соответствия RFC5961 в тестируемом устройстве.
Примечание: тестируемое устройство использует маленькое окно и недолговечные сокеты, поэтому проблема спорна, поскольку DUT на самом деле не уязвим для атаки DOS. Но попробуйте убедить в этом клиента, когда он потратил непомерную сумму денег на тестовое приложение, а оно просто ошибочно сообщает, что это открытая атака.
Подробнее здесь: https://stackoverflow.com/questions/792 ... from-a-syn
Мобильная версия