Сегодня я инвестировал немного больше времени, чтобы узнать о ARP-пакетах. Чтобы понять его структуру, я попытался построить один на себе в C, используя libpcap
. Я структурировал простой пакет запроса ARP и использовал функцию pcap_inject
для отправки пакета. Эта функция возвращает количество отправленных байтов.Как структурировать и пакет запроса ARP в C
Когда я отлаживаю свой код, я увидел, что мой пакет был длиной 42 байта. Я немного искал в Интернете и не смог найти ответ, который говорит мне, является ли это подходящим размером для запроса ARP или нет. Даже wikipedia entry немного смутил меня. И я открыл этот пост. Из ответа, предоставленного пользователем:
- Если сообщение ARP должны быть отправлено в немаркированном кадре, то сам кадр накладного расходы составляют 18 байт. Это приведет к созданию кадра 28 + 18 = 46 байт без заполнения. Дополнительные 18 байтов заполнения - , необходимые в этом случае, чтобы раздуть рамку до длины в 64 байта.
- Если сообщение ARP должно быть отправлено в фрейме с отметкой 802.1Q, то служебные данные кадра составляют 22 байта, в результате чего общий размер кадра 28 + 22 = 50 байт. В этом случае прокладка должна быть 14 байтов.
- Если сообщение ARP должно быть отправлено в двойном теге, тогда служебные данные кадра составляют 26 байтов, в результате общий размер кадра составляет 54 байт. В этом случае длина прокладки должна быть 10 байтов.
Вопрос в том, что мне нужно сделать в этой ситуации. Нужно ли использовать прокладку или нет?
Bellow Я размещаю структуру своего пакета.
#define ETH_P_ARP 0x0806 /* Address Resolution packet */
#define ARP_HTYPE_ETHER 1 /* Ethernet ARP type */
#define ARP_PTYPE_IPv4 0x0800 /* Internet Protocol packet */
/* Ethernet frame header */
typedef struct {
uint8_t dest_addr[ETH_ALEN]; /* Destination hardware address */
uint8_t src_addr[ETH_ALEN]; /* Source hardware address */
uint16_t frame_type; /* Ethernet frame type */
} ether_hdr;
/* Ethernet ARP packet from RFC 826 */
typedef struct {
uint16_t htype; /* Format of hardware address */
uint16_t ptype; /* Format of protocol address */
uint8_t hlen; /* Length of hardware address */
uint8_t plen; /* Length of protocol address */
uint16_t op; /* ARP opcode (command) */
uint8_t sha[ETH_ALEN]; /* Sender hardware address */
uint32_t spa; /* Sender IP address */
uint8_t tha[ETH_ALEN]; /* Target hardware address */
uint32_t tpa; /* Target IP address */
} arp_ether_ipv4;
В конце концов, я просто скопировать каждый элемент структуры в сильфона порядке и отправить пакет:
void packageARP(unsigned char *buffer, ether_hdr *frameHeader, arp_ether_ipv4 *arp_packet, size_t *bufferSize) {
unsigned char *cp;
size_t packet_size;
cp = buffer;
packet_size = sizeof(frameHeader->dest_addr)
+ sizeof(frameHeader->src_addr)
+ sizeof(frameHeader->frame_type)
+ sizeof(arp_packet->htype)
+ sizeof(arp_packet->ptype)
+ sizeof(arp_packet->hlen)
+ sizeof(arp_packet->plen)
+ sizeof(arp_packet->op)
+ sizeof(arp_packet->sha)
+ sizeof(arp_packet->spa)
+ sizeof(arp_packet->tha)
+ sizeof(arp_packet->tpa);
/*
* Copy the Ethernet frame header to the buffer.
*/
memcpy(cp, &(frameHeader->dest_addr), sizeof(frameHeader->dest_addr));
cp += sizeof(frameHeader->dest_addr);
memcpy(cp, &(frameHeader->src_addr), sizeof(frameHeader->src_addr));
cp += sizeof(frameHeader->src_addr);
/* Normal Ethernet-II framing */
memcpy(cp, &(frameHeader->frame_type), sizeof(frameHeader->frame_type));
cp += sizeof(frameHeader->frame_type);
/*
* Add the ARP data.
*/
memcpy(cp, &(arp_packet->htype), sizeof(arp_packet->htype));
cp += sizeof(arp_packet->htype);
memcpy(cp, &(arp_packet->ptype), sizeof(arp_packet->ptype));
cp += sizeof(arp_packet->ptype);
memcpy(cp, &(arp_packet->hlen), sizeof(arp_packet->hlen));
cp += sizeof(arp_packet->hlen);
memcpy(cp, &(arp_packet->plen), sizeof(arp_packet->plen));
cp += sizeof(arp_packet->plen);
memcpy(cp, &(arp_packet->op), sizeof(arp_packet->op));
cp += sizeof(arp_packet->op);
memcpy(cp, &(arp_packet->sha), sizeof(arp_packet->sha));
cp += sizeof(arp_packet->sha);
memcpy(cp, &(arp_packet->spa), sizeof(arp_packet->spa));
cp += sizeof(arp_packet->spa);
memcpy(cp, &(arp_packet->tha), sizeof(arp_packet->tha));
cp += sizeof(arp_packet->tha);
memcpy(cp, &(arp_packet->tpa), sizeof(arp_packet->tpa));
cp += sizeof(arp_packet->tpa);
*bufferSize = packet_size;
}
Является ли это правильный способ структурирования пакет запроса ARP?
Привет, Гил, спасибо за ваш ответ. Я добавил поле 'attribute', как вы предложили. Для полей 'uint16_t' и' uint32_t' я использую 'htons'. Это неправильно? Я также хотел спросить, какова должна быть ценность целевого MAC, поскольку это то, что мы хотим узнать. Я использую 'unsigned char arp_tha [6] = {0, 0, 0, 0, 0, 0};' –
'htons' является хостом для сети- * short * (16-бит/uint16_t). 'htonl' является длиной от сети к сети (32-бит/uint32_t). Установка 'tha' для всех нулей правильная. Его значение в запросе следует игнорировать в любом случае. Это (адрес целевого оборудования) - это то, что вы ищете, совершая транзакцию ARP. –