public inbox for libc-help@sourceware.org
 help / color / mirror / Atom feed
* How to get ICMP reply packet correctly?
@ 2021-03-03 20:01 Peng Yu
  0 siblings, 0 replies; only message in thread
From: Peng Yu @ 2021-03-03 20:01 UTC (permalink / raw)
  To: libc-help

[-- Attachment #1: Type: text/plain, Size: 4091 bytes --]

Hi,

When I run the following program on Linux. It prints like this. The
source and destination IP addresses ("08 08 08 08 c0 a8 01 68") are on
the data (pckt.msg) of ICMP reply packet. What are "76 01 72 89"?

I don't think ICMP data should have such IP addresses. And I check
with tcpdump. The packet received by tcpdump is correct.

Therefore, I think there is something wrong with the receive code in
my program. Could anybody help make the program correctly receive the
packet. (I still want to send the raw packet as is.) Thanks.

$ ./main 8.8.8.8
sin_family = 2
s_addr = 8080808
sin_port = 0
Packet received with ICMP type 69 code 0
pckt.hdr.checksum 5400
id=0 sequence=0, ttl=96
76 01 72 89 08 08 08 08 c0 a8 01 68 00 00 c8 a2 83 01 78 03 30 31 32
33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49
4a 4b 4c 4d 4e 4f 50 51 52 53

$ cat main.c
// vim: set noexpandtab tabstop=2:

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <time.h>

// Gives the timeout delay for receiving packets
// in seconds
#define RECV_TIMEOUT 1

// ping packet size
#define PING_PKT_S 64
// ping packet structure
struct ping_pkt {
    struct icmphdr hdr;
    unsigned char msg[PING_PKT_S-sizeof(struct icmphdr)];
};

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;
}

int main(int argc, char *argv[]) {
    struct sockaddr_in addr_con;
    addr_con.sin_family = AF_INET;
    addr_con.sin_port = htons(0);

    const char *server_ip_addr = argv[1];
    int rval;
    if((rval = inet_pton(AF_INET, server_ip_addr,
&addr_con.sin_addr.s_addr)) == 0) {
        fprintf(stderr, "Invalid IPv4 address: %s\n", server_ip_addr);
        return 1;
    } else if(rval == -1) {
        perror("inet_pton()");
        return 1;
    }

    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if(sockfd<0) {
        perror("socket()");
        return 1;
    }

    // set socket options at ip to TTL and value to 64,
    // change to what you want by setting ttl_val
    int ttl_val=96;
    if (setsockopt(sockfd, SOL_IP, IP_TTL,  &ttl_val, sizeof(ttl_val)) != 0) {
        perror("setsockopt()");
        return 1;
    }

    // setting timeout of recv setting
    struct timeval tv_out;
    tv_out.tv_sec = RECV_TIMEOUT;
    tv_out.tv_usec = 0;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv_out,
sizeof tv_out);

    // send icmp packet in an infinite loop
    struct ping_pkt pckt;
    memset(&pckt, 0, sizeof(pckt));
    pckt.hdr.type = ICMP_ECHO;
    pckt.hdr.un.echo.id = 387;
    pckt.hdr.un.echo.sequence = 888;

    for (int i = 0; i < sizeof(pckt.msg); i++)
        pckt.msg[i] = i+'0';

    pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));

    //send packet
    if (sendto(sockfd, &pckt, sizeof(pckt), 0,
                (struct sockaddr*) &addr_con,
                sizeof(addr_con)) <= 0) {
        puts("Packet Sending Failed!");
        return 1;
    }

    //receive packet
    struct sockaddr_in r_addr;
    unsigned int addr_len=sizeof(r_addr);
    if (recvfrom(sockfd, &pckt, sizeof(pckt), 0, (struct
sockaddr*)&r_addr, &addr_len) <= 0) {
        puts("Packet receive failed!");
    } else {
        printf("sin_family = %0x\n", r_addr.sin_family);
        printf("s_addr = %0x\n", r_addr.sin_addr.s_addr);
        printf("sin_port = %0x\n", r_addr.sin_port);

        printf("Packet received with ICMP type %d code %d\n",
pckt.hdr.type, pckt.hdr.code);
        printf("pckt.hdr.checksum %04x\n", pckt.hdr.checksum);
        printf("id=%d sequence=%d, ttl=%d\n", pckt.hdr.un.echo.id,
pckt.hdr.un.echo.sequence, ttl_val);

        for(int i=0; i<sizeof(pckt.msg); ++i) {
            printf("%02x ", pckt.msg[i]);
        }
        puts("");
    }
    return 0;
}


-- 
Regards,
Peng

[-- Attachment #2: main.c --]
[-- Type: application/octet-stream, Size: 2928 bytes --]

// vim: set noexpandtab tabstop=2:

#include <stdio.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <netinet/ip_icmp.h> 
#include <time.h> 

// Gives the timeout delay for receiving packets 
// in seconds 
#define RECV_TIMEOUT 1  

// ping packet size 
#define PING_PKT_S 64 
// ping packet structure 
struct ping_pkt { 
	struct icmphdr hdr; 
	unsigned char msg[PING_PKT_S-sizeof(struct icmphdr)]; 
}; 

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; 
} 

int main(int argc, char *argv[]) { 
	struct sockaddr_in addr_con;
	addr_con.sin_family = AF_INET;
	addr_con.sin_port = htons(0);

	const char *server_ip_addr = argv[1];
	int rval;
	if((rval = inet_pton(AF_INET, server_ip_addr, &addr_con.sin_addr.s_addr)) == 0) {
		fprintf(stderr, "Invalid IPv4 address: %s\n", server_ip_addr);
		return 1;
	} else if(rval == -1) {
		perror("inet_pton()");
		return 1;
	}

	int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
	if(sockfd<0) { 
		perror("socket()"); 
		return 1; 
	}

	// set socket options at ip to TTL and value to 64, 
	// change to what you want by setting ttl_val 
	int ttl_val=96;
	if (setsockopt(sockfd, SOL_IP, IP_TTL,  &ttl_val, sizeof(ttl_val)) != 0) { 
		perror("setsockopt()"); 
		return 1; 
	}

	// setting timeout of recv setting 
	struct timeval tv_out; 
	tv_out.tv_sec = RECV_TIMEOUT;
	tv_out.tv_usec = 0;
	setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv_out, sizeof tv_out);

	// send icmp packet in an infinite loop 
	struct ping_pkt pckt; 
	memset(&pckt, 0, sizeof(pckt)); 
	pckt.hdr.type = ICMP_ECHO; 
	pckt.hdr.un.echo.id = 387;
	pckt.hdr.un.echo.sequence = 888;

	for (int i = 0; i < sizeof(pckt.msg); i++) 
		pckt.msg[i] = i+'0';

	pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));

	//send packet
	if (sendto(sockfd, &pckt, sizeof(pckt), 0,
				(struct sockaddr*) &addr_con,
				sizeof(addr_con)) <= 0) {
		puts("Packet Sending Failed!");
		return 1;
	}

	//receive packet
	struct sockaddr_in r_addr; 
	unsigned int addr_len=sizeof(r_addr);
	if (recvfrom(sockfd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&r_addr, &addr_len) <= 0) {
		puts("Packet receive failed!");
	} else {
		printf("sin_family = %0x\n", r_addr.sin_family);
		printf("s_addr = %0x\n", r_addr.sin_addr.s_addr);
		printf("sin_port = %0x\n", r_addr.sin_port);

		printf("Packet received with ICMP type %d code %d\n", pckt.hdr.type, pckt.hdr.code);
		printf("pckt.hdr.checksum %04x\n", pckt.hdr.checksum);
		printf("id=%d sequence=%d, ttl=%d\n", pckt.hdr.un.echo.id, pckt.hdr.un.echo.sequence, ttl_val);

		for(int i=0; i<sizeof(pckt.msg); ++i) {
			printf("%02x ", pckt.msg[i]);
		}
		puts("");
	}
	return 0;
} 

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-03-03 20:01 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-03 20:01 How to get ICMP reply packet correctly? Peng Yu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).