Skip to content

Instantly share code, notes, and snippets.

@incebellipipo
Created August 4, 2018 16:10
Show Gist options
  • Save incebellipipo/e31bf4ad3d8bfc1280222838239c7687 to your computer and use it in GitHub Desktop.
Save incebellipipo/e31bf4ad3d8bfc1280222838239c7687 to your computer and use it in GitHub Desktop.
Ping C++11 implementation
/*
* 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