添加printf更改sendTo因失败而导致的成功

时间:2012-11-28 14:25:34

标签: c sockets network-programming

我知道这听起来很奇怪。 printf不应该改变任何东西,但没有它sendTo失败。 该程序是从c代码复制的,并由ubuntux86上的cpp编译器编译。 我有一个发送arp请求的程序。没有这个printf,sendTo失败了。 奇怪的是,我做了一个最小的程序,根本不在printf变量中使用(仅在printf中),并且printf工作,没有printf它不起作用(在sendTo上获得无效的参数错误)。

附件是仅用于显示问题的最小版本:

此sendTo失败:

int retVal = sendto(arp_fd, &pkt, sizeof(pkt), 0, (struct sockaddr *) &sa,sizeof(sa));
if (retVal < 0) {
    perror("sendto");
    close(arp_fd);
    exit(1);
}

添加时它起作用:

struct ifreq ifr;//There is no use except in the printf
printf("MAC address: is %02x:%02x:%02x:%02x:%02x:%02x \n",
        ifr.ifr_hwaddr.sa_data[0]&0xFF,
        ifr.ifr_hwaddr.sa_data[1]&0xFF,
        ifr.ifr_hwaddr.sa_data[2]&0xFF,
        ifr.ifr_hwaddr.sa_data[3]&0xFF,
        ifr.ifr_hwaddr.sa_data[5]&0xFF,
        ifr.ifr_hwaddr.sa_data[4]&0xFF);

完整的计划:

#include "sys/socket.h"
#include "sys/types.h"
#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "net/if.h"
#include "stdlib.h"
#include "arpa/inet.h"
#include "netinet/in.h"
#include "sys/ioctl.h"
#include "netpacket/packet.h"
#include "net/ethernet.h"

#define ETHER_TYPE_FOR_ARP 0x0806
#define HW_TYPE_FOR_ETHER 0x0001
#define OP_CODE_FOR_ARP_REQ 0x0001
#define HW_LEN_FOR_ETHER 0x06
#define HW_LEN_FOR_IP 0x04
#define PROTO_TYPE_FOR_IP 0x0800

typedef unsigned char byte1;
typedef unsigned short int byte2;
typedef unsigned long int byte4;

// For Proper memory allocation in the structure
#pragma pack(1)
typedef struct arp_packet {
// ETH Header
    byte1 dest_mac[6];
    byte1 src_mac[6];
    byte2 ether_type;
// ARP Header
    byte2 hw_type;
    byte2 proto_type;
    byte1 hw_size;
    byte1 proto_size;
    byte2 arp_opcode;
    byte1 sender_mac[6];
    byte4 sender_ip;
    byte1 target_mac[6];
    byte4 target_ip;
// Paddign
    char padding[18];
} ARP_PKT;

int main() {
    struct sockaddr_ll sa;

// Ethernet Header
    ARP_PKT pkt;
    memset(pkt.dest_mac, 0xFF, (6 * sizeof(byte1)));
    memset(pkt.src_mac, 0x1, (6 * sizeof(byte1)));
    pkt.ether_type = htons(ETHER_TYPE_FOR_ARP);
// ARP Header
    pkt.hw_type = htons(HW_TYPE_FOR_ETHER);
    pkt.proto_type = htons(PROTO_TYPE_FOR_IP);
    pkt.hw_size = HW_LEN_FOR_ETHER;
    pkt.proto_size = HW_LEN_FOR_IP;
    pkt.arp_opcode = htons(OP_CODE_FOR_ARP_REQ);
    memcpy(pkt.sender_mac, pkt.src_mac, (6 * sizeof(byte1)));
    pkt.sender_ip = 2449647808;
    memset(pkt.target_mac, 0, (6 * sizeof(byte1)));
    pkt.target_ip = inet_addr("10.0.0.10");
// Padding
    memset(pkt.padding, 0, 18 * sizeof(byte1));

    sa.sll_family = AF_PACKET;
    sa.sll_ifindex = 3;
    sa.sll_protocol = htons(ETH_P_ARP);

    /* Send it! */
    int arp_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    struct ifreq ifr;
    printf("MAC address: is %02x:%02x:%02x:%02x:%02x:%02x \n",
            ifr.ifr_hwaddr.sa_data[0]&0xFF,
            ifr.ifr_hwaddr.sa_data[1]&0xFF,
            ifr.ifr_hwaddr.sa_data[2]&0xFF,
            ifr.ifr_hwaddr.sa_data[3]&0xFF,
            ifr.ifr_hwaddr.sa_data[5]&0xFF,
            ifr.ifr_hwaddr.sa_data[4]&0xFF);
    int retVal = sendto(arp_fd, &pkt, sizeof(pkt), 0, (struct sockaddr *) &sa,sizeof(sa));
    if (retVal < 0) {
        perror("sendto");
        close(arp_fd);
        exit(1);
    }

    printf("\n=========PACKET=========\n");
    return 0;
}

1 个答案:

答案 0 :(得分:2)

这是因为您在struct sockaddr_ll sa中有未初始化的值。更具体地说,您对printf的调用强制编译器在堆栈上保存三个寄存器,从而移动sa位置及其值。您可以在printf("halen %p %d\n", &sa.sll_halen, sa.sll_halen);之前printf 看到它发生变化,具体取决于您是否添加了printf

只需添加sa.sll_halen = 0;即可查看差异......并为您的真实程序初始化整个结构。