结构复制到字节数组..对齐错误?

Struct copied into byte array .. wrong alignement?

我正在尝试通过网络发送一些手动制作的 ARP 数据包,更具体地说,是一个获取主机 MAC 地址的 ARP 请求。 我无法获得正确的最终数据包,在 wireshark 上它仍然显示出一些不一致。 让我来引导你: 这是我在整个程序中使用的结构和类型定义, 我已经定义

代码:

#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 地址。但是由于这个偏移量,不可能正确解析这个数据包。例如,在 wireshark 中,我得到的不是“10.0.0.1”,而是 IP 的“0.0.10.0”。 这是 GDB 的成绩单:

/** 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"中,所有信息都是正确的,即 struct Host 包含好的信息等;我已经检查了一切。 我只是没有得到 2 个字节的偏移量......在旧版本中,没有使用所有这些新结构(仅 char *),我已经成功创建了正确的 ARP 数据包,所以我有点想知道如果这不是结构的原因,但我对 C 的了解没有扩展到内存对齐主题...!

谢谢。

问题是你的结构没有打包。一种解决方案是使用打包结构,即

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 的扩展。

在我看来,最好的解决方案是直接访问字节数组的元素,而不是使用结构。是的,它添加了几行代码,但它保证适用于不实现打包结构的编译器。