2015-03-20 10 views
0

Я пытаюсь отправить некоторые ARP-пакеты вручную с помощью сети, более конкретно, ARP-запрос для получения MAC-адреса хоста. Я не могу получить окончательный пакет вправо, на проводах, он все еще показывает некоторую несогласованность. Позвольте мне вас через: Вот структура & ЬурейеЕ Я использую все по программе, я определилСтруктура, скопированная в массив байтов .. неправильное выравнивание?

  • IP STRUCT (=> in_addr)
  • УДС структура (=> ether_addr)
  • хост структура состоит из MAC & IP
  • пользовательских структур для представления Ethernet кадра & кадр ARP.

Код:

#define ETH_ADDR_SIZE 6 
#define IP_ADDR_SIZE 4 
typedef u_char Packet; 
typedef struct in_addr IP; 
typedef struct ether_addr MAC; 

struct Host { 
    IP ip; 
    MAC mac; 
}; 
typedef struct pkt_eth { 
    MAC dest; 
    MAC src; 
    u_short type; 
} pkt_eth; 

typedef struct pkt_arp { 
    u_short htype;/* hardware type => ethernet , etc */ 
    u_short ptype; /*protocol type => ipv4 or ipv6 */ 
    u_char hard_addr_len; /* usually 6 bytes for ethernet */ 
    u_char proto_addr_len; /*usually 8 bytes for ipv4 */ 
    u_short opcode; /* type of arp */ 
    MAC hard_addr_send; 
    IP proto_addr_send; 
    MAC hard_addr_dest; 
    IP proto_addr_dest; 
} pkt_arp; 

/* Designate our own MAC/IP addresses of the interface */ 
extern MAC mac; 
extern IP ip; 
extern char * interface; 

/* Just some vars used to compare with the struct we use */ 
const MAC broadcast_mac = { 0xff,0xff,0xff,0xff,0xff,0xff }; 
const MAC null_mac = { 0x00,0x00,0x00,0x00,0x00,0x00 }; 
const IP broadcast_ip = { 0xffffffff }; 
const IP null_ip = { 0x00000000 }; 
const struct Host null_host = {{ 0x00000000 }, 
          { 0x00,0x00,0x00,0x00,0x00,0x00 }}; 

/* Empty mac address which can be used as a temp variable */ 
MAC tmp_mac = { 0x00,0x00,0x00,0x00,0x00,0x00 }; 
IP tmp_ip = { 0x00000000 }; 

Вот соответствующая функция:

int 
arp_resolve_mac (struct Host * host) 
{ 
    struct pkt_arp * arp; 
    struct pkt_eth * eth; 
    /*Create the request packet */ 
    Packet * request = arp_packet(REQUEST); 
    eth = (struct pkt_eth *) (request); 
    arp = (struct pkt_arp *) (request + ETH_SIZE); 

    /* ethernet frame */ 
    copy_mac(&eth->dest,&broadcast_mac); 
    copy_mac(&eth->src,&mac); 

    /* arp request => mac dest address set to null */ 
    copy_mac(&arp->hard_addr_send,&mac); 
    copy_mac(&arp->hard_addr_dest,&null_mac); 

    /* arp request => target ip ! */ 
    copy_ip(&arp->proto_addr_send,&ip); 
    copy_ip(&arp->proto_addr_dest,&host->ip); 

    /* Set up sniffing. Better to do it before so less 
    * prepare time and if any error occurs, no need to send 
    * the packet. less intrusive */ 
    pcap_init(interface,"arp"); 
    pcap_set_arp_analyzer(arp_analyzer_resolv); 

    /* Sets the tmp ip variable so we will know if it the right 
    * response we get or a response coming from another source */ 
    tmp_ip = host->ip; 
    /* sends the packet */ 
    if(pcap_send_packet(request,ARP_PACKET_SIZE) == -1) { 
     fprintf(stderr,"Error while sending ARP request packet.\n"); 
     return -1; 
    } 
    .... 
    } 
Packet * 
arp_packet (int opcode) 
{ 
    struct pkt_arp * arp; 
    struct pkt_eth * eth; 
    Packet * bytes = (Packet *) malloc(ARP_PACKET_SIZE); 

    if(bytes == NULL) { 
     fprintf(stderr,"Could not alloc ARP packet.\n"); 
     return NULL; 
    } 
    eth = (struct pkt_eth *) (bytes); 
    eth->type = htons(ETHERTYPE_ARP); 

    /* length about hard/proto ... */ 
    arp = (struct pkt_arp *) (bytes + ETH_SIZE); 
    arp->htype = htons(1); 
    arp->ptype = htons(0x0800); 
    arp->hard_addr_len = ETH_ADDR_SIZE; 
    arp->proto_addr_len = IP_ADDR_SIZE; 
    /* reply or request */ 
    arp->opcode = opcode == REQUEST ? htons(ARPOP_REQUEST) : htons(ARPOP_REPLY); 

    return bytes; 
}  /* ----- end of function arp_empty ----- */ 


void copy_mac(MAC * m1,const MAC * m2) { 
    memcpy(m1,m2,ETH_ADDR_SIZE); 
} 
void copy_ip(IP * i1,const IP * i2) { 
    memcpy(i1,i2,IP_ADDR_SIZE); 
} 
void copy_host(struct Host * h1,const struct Host * h2) { 
    copy_mac(&h1->mac,&h2->mac); 
    copy_ip(&h1->ip,&h2->ip); 
} 

Проблема: Созданный пакет не совсем верно. Все хорошо до hard_addr_send. После этого поля есть 2 байта 0x00,0x00, (см. В GDB), а затем IP-адрес. Но из-за этого смещения невозможно правильно разобрать этот пакет. Например, в wirehark вместо получения «10.0.0.1» у меня есть «0.0.10.0» для IP. Вот расшифровка БГДА:

/** 14 to pass ethernet frame & 4 + 2 + 2 to go to the addresses section*/ 
(gdb) x/6xb request+14+4+2+2 
/** My MAC address , field hard_addr_send. it's GOOD. */ 
0x606b16: 0x34 0x67 0x20 0x01 0x9a 0x67 
(gdb) x/6xb request+14+4+2+2+6 
/** 6bytes later, supposedly my IP address. 
* It should be 10.0.0.7 but you can see the 0x0a shifted by 2 bytes */ 
0x606b1c: 0x00 0x00 0x0a 0x00 0x00 0x07 

В методе «arp_resolv_mac», вся информация верна, то есть структура хост содержит полезную информацию и т.д.; Я проверил все. Я просто не получаю это смещение на 2 байта ... В старых версиях, не используя все тезисы new structs (только char *), мне уже удалось создать правильный пакет ARP, поэтому я отчасти интересно, не связано ли это с конструкцией, но мои знания о C не распространяются на объект привязки к памяти ...!

спасибо.

+0

В C компилятор может собирать или размещать информацию в 'struct' по своему усмотрению. Поэтому, если вы хотите конвертировать назад и вперед между массивом байтов и 'struct', вам нужно будет копировать элементы по отдельности, чтобы гарантировать выравнивание. – lurker

+0

Не является ли «нормальное выравнивание» (каждый член присоединен друг к другу в том же порядке, что и в определении) по умолчанию? – Nikkolasg

+0

Они были бы в порядке, но, возможно, дополнены. На выравнивание влияет заполнение. – lurker

ответ

1

Проблема в том, что ваши структуры не упакованы. Одним из решений могло бы быть использование упакованных структур, т.е.

typedef struct __attribute__ ((__packed__)) pkt_arp { 
    u_short htype;/* hardware type => ethernet , etc */ 
    u_short ptype; /*protocol type => ipv4 or ipv6 */ 
    u_char hard_addr_len; /* usually 6 bytes for ethernet */ 
    u_char proto_addr_len; /*usually 8 bytes for ipv4 */ 
    u_short opcode; /* type of arp */ 
    MAC hard_addr_send; 
    IP proto_addr_send; 
    MAC hard_addr_dest; 
    IP proto_addr_dest; 
} pkt_arp; 

Тем не менее, что является GCC конкретным расширением другие компиляторы могут не поддерживать.

На мой взгляд, лучшим решением является обращение к элементам байтового массива напрямую, а не использование структур. Да, он добавляет несколько строк кода, но он гарантированно работает для компиляторов, которые также не реализуют упакованные структуры.

+0

Не могли бы вы объяснить немного больше об этом упакованном атрибуте? И я думал по умолчанию, члены структуры были выровнены «правильно», т. Е. все члены прикреплены таким же образом, как это было объявлено? – Nikkolasg

+0

Ìt работает !! Большое спасибо ! вы сохранили еще один день пыток с проверкой памяти! Может быть, я тогда вернусь к простому массиву. – Nikkolasg

+1

Если вы определяете следующую структуру: struct mystruct {uint16_t x; uint32_t y; }, тогда длина структуры будет 8 байтов из-за требования 4-байтного выравнивания uint32_t. Таким образом, он имеет 2 байта x, 2 байта заполнения и 4 байта y. Если вы используете упакованные структуры, то отступы устраняются. Недостатком является то, что на некоторых архитектурах вы не можете иметь указатели на элементы упакованных структур. – juhist