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

时间:2015-03-20 20:24:38

标签: c struct pcap memory-alignment arp

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

  • 一个IP结构(=> in_addr)
  • MAC结构(=> ether_addr)
  • 由MAC&组成的主机结构。 IP
  • 自定义结构代表以太网帧& 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地址。但由于这种偏移,无法正确解析此数据包。例如,在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的了解并没有延伸到记忆对象的主题......!

谢谢。

1 个答案:

答案 0 :(得分: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的扩展。

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