Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带数据的ICMP请求_C_Sockets_Icmp - Fatal编程技术网

带数据的ICMP请求

带数据的ICMP请求,c,sockets,icmp,C,Sockets,Icmp,我想发送ICMP请求消息,末尾有一些数据。我只能发送没有数据的简单ICMP请求。当我想在缓冲区中icmp结构的末尾添加一些字符时,不会发送icmp请求。当我删除结束字符或将sendto函数中发送消息的大小更改为sizeof(icmp)时,消息正常发送。怎么了 ping函数中的参数没有问题 void ping(struct sockaddr_in *addr) { int sd; const int val=255; struct sockaddr_in r_addr;

我想发送ICMP请求消息,末尾有一些数据。我只能发送没有数据的简单ICMP请求。当我想在缓冲区中icmp结构的末尾添加一些字符时,不会发送icmp请求。当我删除结束字符或将sendto函数中发送消息的大小更改为sizeof(icmp)时,消息正常发送。怎么了

ping函数中的参数没有问题

void ping(struct sockaddr_in *addr) {
    int sd;
    const int val=255;
    struct sockaddr_in r_addr;
    sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
    if ( sd < 0 ) {
        perror("socket");
        return;
    }
    if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
        perror("Set TTL option");
    if ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )
        perror("Request nonblocking I/O");
    socklen_t len=sizeof(r_addr);
    struct icmp *icmp_send, *icmp_recv;
    icmp_send->icmp_type = ICMP_ECHO;
    icmp_send->icmp_code = 0;
    icmp_send->icmp_id = getpid();
    icmp_send->icmp_seq = 1;
    icmp_send->icmp_cksum = 0;
    icmp_send->icmp_cksum = checksum(icmp_send, sizeof(icmp_send));
    unsigned char buff[2000];
    unsigned char*p = buff;
    memcpy(buff, icmp_send, sizeof(icmp)); 
    p += sizeof(icmp);
    *p = 'A';
    if ( sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1 , 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 ) {
                printf("Send err.\n");
    }
}
void ping(结构sockaddr\u in*addr){
国际标准差;
常数int val=255;
r_addr中的结构sockaddr_;
sd=插座(PF_INET、SOCK_RAW、IPPROTO_ICMP);
如果(sd<0){
佩罗(“插座”);
返回;
}
如果(设置锁定选项(sd、SOL_IP、IP_TTL和val、sizeof(val))!=0)
perror(“设置TTL选项”);
如果(fcntl(sd,F_设置FL,O_非块)!=0)
perror(“请求非阻塞I/O”);
socklen_t len=大小(r_addr);
结构icmp*icmp\u发送,*icmp\u接收;
icmp_发送->icmp_类型=icmp_回显;
icmp_发送->icmp_代码=0;
icmp_发送->icmp_id=getpid();
icmp_发送->icmp_顺序=1;
icmp\u发送->icmp\u校验和=0;
icmp_发送->icmp_校验和=校验和(icmp_发送,sizeof(icmp_发送));
未签名字符buff[2000];
无符号字符*p=buff;
memcpy(buff、icmp_send、sizeof(icmp));
p+=sizeof(icmp);
*p=‘A’;

如果(sendto(sd,(unsigned char*)buff,sizeof(icmp_send)+1,0,(struct sockaddr*)addr,sizeof(*addr))您需要在icmp标头中使用附加到标头的字节重新计算校验和


实现这一点的最佳方法是初始化
*icmp\u send
以指向您的
buff
字符串,然后在那里损坏您的字段。这将避免您从
*icmp\u send
buff
访问
memcpy
。下面是一个示例

unsigned char buff[2000];
unsigned char *p = buff;
struct icmp *icmp_send;

icmp_send = (struct icmp *)buff;
icmp_send->icmp_type = ICMP_ECHO;
icmp_send->icmp_code = 0;
icmp_send->icmp_id = getpid();
icmp_send->icmp_cksum = 0;
icmp_send->icmp_seq = htons(1);
p += sizeof(icmp_send);
*p = 'A';

icmp_send->icmp_cksum = checksum(buff, sizeof(icmp_send) + 1);

if ( sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1, 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 ) {
            printf("Send err.\n");
} 
在下文中填写代码(OT:如果需要,确保在通过网络发送数据时使用hton功能)

无符号短校验和(void*b,int len)
{无符号短*buf=b;
无符号整数和=0;
无符号短结果;
对于(总和=0;len>1;len-=2)
总和+=*buf++;
如果(len==1)
sum+=*(无符号字符*)buf;
总和=(总和>>16)+(总和&0xFFFF);
总和+=(总和>>16);
结果=~sum;
返回结果;
}
无效ping(在*addr中的结构sockaddr_){
国际标准差;
常数int val=255;
r_addr中的结构sockaddr_;
sd=插座(PF_INET、SOCK_RAW、IPPROTO_ICMP);
如果(sd<0){
佩罗(“插座”);
返回;
}
如果(设置锁定选项(sd、SOL_IP、IP_TTL和val、sizeof(val))!=0)
perror(“设置TTL选项”);
如果(fcntl(sd,F_设置FL,O_非块)!=0)
perror(“请求非阻塞I/O”);
socklen_t len=大小(r_addr);
结构icmp*icmp\u发送,*icmp\u接收;
icmp_发送->icmp_类型=icmp_回显;
icmp_发送->icmp_代码=0;
icmp_发送->icmp_id=getpid();
icmp_send->icmp_seq=htons(1);
未签名字符buff[2000];
无符号字符*p=buff;
p+=sizeof(icmp_发送);
*p=‘A’;
icmp\u发送->icmp\u校验和=0;
memcpy(buff、icmp_send、sizeof(icmp_send));
icmp_发送->icmp_校验和=校验和(buff,sizeof(icmp_发送)+1);
memcpy(buff、icmp_send、sizeof(icmp_send));

如果(SDETO(未签名的CHAR *)buff,siZeof(ICMPSORDER)+1, 0,(StutoSokAdDr*),ADDR,siZeof(*ADDR))C!= C++ +。标签只与您使用的语言,除非两者实际上是相关的。您的<代码> *ICMPXEng/<代码>未初始化。您显然知道<代码> PrRor ,为什么打印“发送错误”。相反?您不需要在修改缓冲区后和发送数据包之前重新计算校验和吗?这里给出了一个很好的例子:“实现这一点的最佳方法是初始化
*icmp_send
以指向您的
buff
字符串,然后在那里损坏字段。”如果您的平台没有x86那么宽容不一致的访问,那么您必须小心这类把戏。通常情况下,最好安全地使用
memcpy
。我根据您的评论更新了我的答案,谢谢Matteo。您好@stepanVich,您能接受答案吗?或者如果您需要更多信息,请告诉我如何更新我可以帮忙。
...
unsigned char*p = buff;
p += sizeof(icmp_send);
*p = 'A';

// 'A' has been appended into buff right after the header in the previous
// lines, we therefore need to compute the checksum using buff, without
// overwriting 'A', this is why we copy the 8 byte long ICMP header here.
//
// buff looks like [ ICMP HEADER (8 bytes)]['A' (1 byte)]
//
// Before computing the checksum, we also make sure its value in the header
// is set to 0 (mandatory).
icmp_send->icmp_cksum = 0;
memcpy(buff, icmp_send, sizeof(icmp_send));

// Now we can compute the checksum, and have to instruct our checksum()
// function that we want to include the data ('A') by setting the length
// in the second argument to 8 (ICMP header length) + 1 (data length of 'A')
icmp_send->icmp_cksum = checksum(buff, sizeof(icmp_send) + 1);

// Checksum is now ok, lets copy it again to buff. Here we copy the whole
// header but the idea is just to update the ICMP checksum field.
memcpy(buff, icmp_send, sizeof(icmp_send));

// buff contains header + data, ok to send it. Note that you don't need to
// compute the checksum of the IP packet. The system does it for you because
// your socket was created with the IPPROTO_ICMP
if ( sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1, 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 ) {
            printf("Send err.\n");
}
unsigned short checksum(void *b, int len)
{   unsigned short *buf = b;
    unsigned int sum=0;
    unsigned short result;

    for ( sum = 0; len > 1; len -= 2 )
        sum += *buf++;
    if ( len == 1 )
        sum += *(unsigned char*)buf;
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = ~sum;
    return result;
}

void ping(struct sockaddr_in *addr) {
    int sd;
    const int val=255;
    struct sockaddr_in r_addr;
    sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
    if ( sd < 0 ) {
        perror("socket");
        return;
    }
    if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
        perror("Set TTL option");
    if ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )
        perror("Request nonblocking I/O");
    socklen_t len=sizeof(r_addr);
    struct icmp *icmp_send, *icmp_recv;
    icmp_send->icmp_type = ICMP_ECHO;
    icmp_send->icmp_code = 0;
    icmp_send->icmp_id = getpid();
    icmp_send->icmp_seq = htons(1);
    unsigned char buff[2000];
    unsigned char*p = buff;
    p += sizeof(icmp_send);
    *p = 'A';

    icmp_send->icmp_cksum = 0;
    memcpy(buff, icmp_send, sizeof(icmp_send)) ;

    icmp_send->icmp_cksum = checksum(buff, sizeof(icmp_send) + 1);
    memcpy(buff, icmp_send, sizeof(icmp_send)) ;

    if ( sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1, 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 ) {
                printf("Send err.\n");
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2) {
        printf("usage: %s destination_ip\n", argv[0]);
        return 1;
    }

    struct sockaddr_in addr;
    struct in_addr dst;

    if (inet_aton(argv[1], &dst) == 0) {

        perror("inet_aton");
        printf("%s isn't a valid IP address\n", argv[1]);
        return 1;
    }


    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_addr = dst;

    ping(&addr);
    return 0;
}