Created
August 4, 2018 16:10
-
-
Save incebellipipo/e31bf4ad3d8bfc1280222838239c7687 to your computer and use it in GitHub Desktop.
Ping C++11 implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* g++ pingxx.cxx -std=c++11 -lpthread | |
*/ | |
#include <iostream> | |
#include <cstdlib> | |
#include <cstdio> | |
#include <cerrno> | |
#include <cstring> | |
#include <thread> | |
#include <wait.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <sys/socket.h> | |
#include <resolv.h> | |
#include <netdb.h> | |
#include <arpa/inet.h> | |
#include <netinet/in.h> | |
#include <netinet/ip_icmp.h> | |
#define PACKETSIZE 64 | |
struct packet { | |
struct icmphdr hdr; | |
char msg[PACKETSIZE - sizeof(struct icmphdr)]; | |
}; | |
struct pinginfo { | |
struct in_addr src; | |
struct in_addr dst; | |
int ttl; | |
int protocol; | |
int pkgsize; | |
int hdrsize; | |
}; | |
int pid = -1; | |
struct pinginfo pinginf; | |
/*--------------------------------------------------------------------*/ | |
/*--- checksum - standard 1s complement checksum ---*/ | |
/*--------------------------------------------------------------------*/ | |
unsigned int checksum(void *b, int len) { | |
auto *buf = (unsigned short*) b; | |
unsigned int sum = 0; | |
unsigned int result; | |
for ( sum = 0; len > 1; len -= 2 ) { | |
sum += *buf++; | |
} | |
if ( len == 1 ) { | |
sum += *(unsigned char *) buf; | |
} | |
sum = (sum >> 16u) + (sum & 0xFFFFu); | |
sum += (sum >> 16u); | |
result = ~sum; | |
return result; | |
} | |
/*--------------------------------------------------------------------*/ | |
/*--- display - present echo info ---*/ | |
/*--------------------------------------------------------------------*/ | |
void display(void *buf, int bytes) { | |
int i; | |
auto ip = (struct iphdr*) buf; | |
auto icmp = (struct icmphdr *) buf + (ip->ihl * 4); | |
printf("----------------\n"); | |
for ( i = 0; i < bytes; i++ ) { | |
if ( !(i & 15) ) { | |
printf("\n%X: ", i); | |
} | |
printf("%X ", ((unsigned char*)buf)[i]); | |
} | |
printf("\n"); | |
char saddr[INET_ADDRSTRLEN]; | |
sprintf(saddr, "%d.%u.%u.%u", | |
(ip->saddr >> 0u ) & 0xffu, | |
(ip->saddr >> 8u ) & 0xffu, | |
(ip->saddr >> 16u ) & 0xffu, | |
(ip->saddr >> 24u ) & 0xffu | |
); | |
printf("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d src=%s ", | |
ip->version, | |
ip->ihl*4, | |
ntohs(ip->tot_len), | |
ip->protocol, | |
ip->ttl, | |
saddr); | |
char daddr[INET_ADDRSTRLEN]; | |
sprintf(daddr, "%d.%u.%u.%u", | |
(ip->daddr >> 0u ) & 0xffu, | |
(ip->daddr >> 8u ) & 0xffu, | |
(ip->daddr >> 16u ) & 0xffu, | |
(ip->daddr >> 24u ) & 0xffu | |
); | |
printf("dst=%s\n", daddr); | |
if ( icmp->un.echo.id == pid ) { | |
printf("ICMP: type[%d/%d] checksum[%d] id[%d] seq[%d]\n", | |
icmp->type, icmp->code, ntohs(icmp->checksum), | |
icmp->un.echo.id, icmp->un.echo.sequence); | |
} | |
} | |
/*--------------------------------------------------------------------*/ | |
/*--- listener - separate process to listen for and collect messages--*/ | |
/*--------------------------------------------------------------------*/ | |
void listener() { | |
int sd; | |
struct sockaddr_in addr; | |
memset((void*)&addr, 0 ,sizeof(addr)); | |
unsigned char buf[1024]; | |
sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); | |
if ( sd < 0 ) { | |
perror("socket"); | |
exit(0); | |
} | |
ssize_t bytes; | |
socklen_t len = sizeof(addr); | |
bzero(buf, sizeof(buf)); | |
bytes = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &len); | |
if (bytes > 0) { | |
display(buf, bytes); | |
} else { | |
perror("recvfrom"); | |
} | |
} | |
/*--------------------------------------------------------------------*/ | |
/*--- ping - Create message and send it. ---*/ | |
/*--------------------------------------------------------------------*/ | |
void ping(struct sockaddr_in *addr) { | |
const int val=255; | |
int i, sd, cnt=1; | |
struct packet pckt; | |
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); | |
printf("Msg #%d\n", cnt); | |
if (recvfrom(sd, &pckt, sizeof(pckt), 0, (struct sockaddr *) &r_addr, &len) > 0) { | |
printf("Got message!\n"); | |
} | |
bzero(&pckt, sizeof(pckt)); | |
pckt.hdr.type = ICMP_ECHO; | |
pckt.hdr.un.echo.id = (u_int16_t) pid; | |
for (i = 0; i < sizeof(pckt.msg) - 1; i++) { | |
pckt.msg[i] = (char) i + '0'; | |
} | |
pckt.msg[i] = 0; | |
pckt.hdr.un.echo.sequence = (u_int16_t) cnt++; | |
pckt.hdr.checksum = (u_int16_t) checksum(&pckt, sizeof(pckt)); | |
if (sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr *) addr, sizeof(*addr)) <= 0) { | |
perror("sendto"); | |
} | |
} | |
/*--------------------------------------------------------------------*/ | |
/*--- main - look up host and start ping processes. ---*/ | |
/*--------------------------------------------------------------------*/ | |
int main(int argc, char *argv[]) { | |
struct hostent *hname; | |
struct sockaddr_in addr; | |
if ( argc != 2 ) { | |
printf("usage: %s <addr>\n", argv[0]); | |
exit(0); | |
} | |
if ( argc > 1 ) { | |
pid = getpid(); | |
hname = gethostbyname(argv[1]); | |
bzero(&addr, sizeof(addr)); | |
addr.sin_family = (sa_family_t) hname->h_addrtype; | |
addr.sin_port = 0; | |
addr.sin_addr.s_addr = *(u_int32_t *)hname->h_addr; | |
if(fork() == 0) { | |
listener(); | |
} else { | |
ping(&addr); | |
} | |
wait(nullptr); | |
} | |
else { | |
printf("usage: ping <hostname>\n"); | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment