(fwd) hping, a tcp pinger

Andrey Gerzhov (kittle@freeland.alex-ua.com)
Sun, 6 Dec 1998 13:22:17 +0200 (EET)

-- forwarded message --
Path: freeland.alex-ua.com!news.alexradio.kiev.ua!not-for-mail
Message-ID: <19981130213757.A2912@seclab.com>
Date: Mon, 30 Nov 1998 21:37:57 +0100
From: antirez <antirez@SECLAB.COM>
Subject: hping, a tcp pinger
To: BUGTRAQ@netspace.org
Newsgroups: alex.gated.bugtraq
Lines: 778
Xref: freeland.alex-ua.com alex.gated.bugtraq:1083

--wac7ysb48OaltWcw
Content-Type: text/plain; charset=us-ascii

Hi,

A few weeks ago, I wrote this little tool.
hping (h? ping) is a tool that fits ping's
concept to the tcp protocol.
In a few words hping can send any kind of
tcp flags and display the target replies
in this format:

[size] bytes from [ip]: flags=[flags] seq=[x] ttl=[y] win=[z] time=[t]ms

This can be usefull for:

- ACL discovery and testing
- Port scanning
- Hide pinging
- Raw fingerprints
- ... Other stuff

These are the 'usage' informations:

#./hping
usage: hping host [options]
c - packets count
i - wait
n - numeric output
q - quiet
I - interface name
p - destination port (default 0)
t - ttl (default 64)
h - shows this help
F - set FIN flag
S - set SYN flag
R - set RST flag
P - set PUSH flag
A - set ACK flag
U - set URG flag
f - splits packets in two fragments
#

hping works only on Linux platform, but I'm
making a libpcap porting.
[ Obviously you must to be root to run hping,
don't setuid it, because like ping program
it's vulnerable to the sigalrm bombing (see
my old posting about pingflood.c for further
informations about this topic). ]

Bye,

antirez

--
Salvatore Sanfilippo
Intesis SECURITY LAB            Phone: +39-02-671563.1
Via Settembrini, 35             Fax: +39-02-66981953
I-20124 Milano  ITALY           Email: antirez@seclab.com

--wac7ysb48OaltWcw Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="hping.c"

/* * hping.c * Copyright (C) 1998 Salvatore Sanfilippo - antirez - <md5330@mclink.it> * <antirez@seclab.com> * This source is covered by the GNU GPL * alpha version, last update 04/12/98 * compile it under linux. (Do you want make a porting?, mail me please) * * Intesis SECURITY LAB Phone: +39-02-671563.1 * Via Settembrini, 35 Fax: +39-02-66981953 * I-20124 Milano ITALY Email: antirez@seclab.com */

#define _BSD_SOURCE

#include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/tcp.h> #include <netinet/ip.h> #include <netinet/in.h> #include <netinet/ip_icmp.h> #include <netdb.h> #include <unistd.h> #include <sys/ioctl.h> #ifdef __GLIBC__ /* please, if this #ifdef doesn't work */ /* with some Linux distr. email me. */ #include <netinet/if_ether.h> /* tested on Debian 2.0 */ #else #include <linux/if_ether.h> /* tested on RedHat 4.1 */ #endif #include <net/if_arp.h> #include <net/if.h> #include <signal.h> #include <time.h> #include <sys/time.h> #include <errno.h>

/* usefull defines */ #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef IFNAMSIZ #define IFNAMSIZ 16 #endif

/* header size of some physical layer type */ #define PPPHDR_SIZE 0 #define ETHHDR_SIZE sizeof(struct ethhdr) #define LOHDR_SIZE sizeof(struct ethhdr) #define UNKNOWNHDR_SIZE 0

/* packet size (physical header size + ip header + tcp header + 0 data bytes) */ #define LINK_PACKETSIZE ( linkhdr_size + \ sizeof(struct iphdr)+ \ sizeof(struct tcphdr) ) /* ip packet size */ #define IP_PACKETSIZE ( sizeof(struct iphdr) + sizeof(struct tcphdr) )

/* absolute offsets */ #define ABS_OFFSETLINK 0 #define ABS_OFFSETIP linkhdr_size #define ABS_OFFSETTCP ( linkhdr_size + sizeof(struct iphdr) ) #define ABS_OFFSETICMP ( linkhdr_size + sizeof(struct iphdr) )

/* ip realtive offsets */ #define IP_OFFSETIP 0 #define IP_OFFSETTCP sizeof(struct iphdr)

/* defaults */ #define DEFAULT_SENDINGWAIT 1 /* wait 1 sec. between sending each packets */ #define DEFAULT_DPORT 0 #define DEFAULT_COUNT -1 /* -1 == forever */ #define DEFAULT_TTL 64

/* fragmentation macros */ #define MORE_FRAGMENTS ((unsigned short)0x2000) #define NO_MORE_FRAGMENTS ((unsigned short)0x0000)

/* globals var */ unsigned int tcp_th_flags = 0; int sockpacket, sockraw, /* sockets fd */ finsent = 0, rstrecv = 0, /* fin sent & reset received */ sending_wait = DEFAULT_SENDINGWAIT, /* see DEFAULT_SENDINGWAIT def*/ linkhdr_size, /* physical layer header size */ opt_numeric = FALSE, opt_quiet = FALSE, fragmentation = FALSE, src_ttl = DEFAULT_TTL, dport = DEFAULT_DPORT, sport, initsport, count = DEFAULT_COUNT; char targetname[1024], /* target hostname */ targetstraddr[1024], ifname[1024] = {'\0'}, /* interface name */ ifstraddr[1024]; /* interface address */ struct sockaddr_in local, remote; struct delaytable_element { int seq; int sec; long usec; }; volatile struct delaytable_element delaytable[20]; int delaytable_index = 0;

/* protos */ int parse_options(int, char**); /* parse command line options */ int get_if_name(void); /* get interface name & addr. */ int get_linkhdrsize(char*); /* get link layer hdr size */ int open_sockpacket(void); /* open SOCK_PACKET socket */ int close_sockpacket(int); /* close SOCK_PACKET socket */ int open_sockraw(void); /* open SOCK_RAW socket */ void sendfin(int); /* send one FIN */ void ip_sender (char*, char*, char*, unsigned int, int, unsigned short); void waitresets(void); /* wait RST replies */ void print_statistics(int); /* print statistics */ void usage(void); /* shows a short help */ void resolver(struct sockaddr*, char*); /* resolver */ void icmpunreach_log(char*, unsigned short); /* logs icmp ureached */ void icmptimeexc_log(char*, unsigned short); /* logs icmp time exc */ long get_utime(void); /* return current usec */ u_short cksum(u_short *buf, int nwords); /* compute 16bit checksum */

/* main */ int main(int argc, char **argv) { if ( parse_options(argc, argv) == -1 ) usage();

/* get interface's name and address */ if ( get_if_name() == -1 ) { printf("[main] no such device\n"); exit(1); }

if ( get_linkhdrsize(ifname) == -1 ) { printf("[main] physical layer header size unknown\n"); exit(1); }

/* trying to open sockpacket socket and raw socket */ sockraw = open_sockraw(); if (sockraw == -1) { printf("[main] can't open raw socket\n"); exit(1); }

sockpacket = open_sockpacket(); if (sockpacket == -1) { printf("[main] can't open packet socket\n"); exit(1); }

resolver((struct sockaddr*)&local, ifstraddr); resolver((struct sockaddr*)&remote, targetname);

srand(time(NULL)); /* randomize */ initsport = 1024 + (rand() % 2000); /* set initial source port */ sport = initsport;

strncpy(targetstraddr, inet_ntoa(remote.sin_addr), sizeof(targetstraddr)); printf("HPING %s (%s %s): %d data bytes\n", targetname, ifname, targetstraddr, IP_PACKETSIZE);

signal(SIGALRM, sendfin); signal(SIGINT, print_statistics); signal(SIGTERM, print_statistics); kill(getpid(), SIGALRM);

waitresets();

return 0; }

int parse_options(int argc, char **argv) { char c;

if (argc < 2) return -1;

strncpy(targetname, argv[1], 1024);

while ( (c = getopt(argc, argv, "c:i:nqI:hp:t:FSRPAUf")) != EOF ) { switch(c) { case '?': return -1; case 'c': count = atoi(optarg); break; case 'i': sending_wait = atoi(optarg); break; case 'n': opt_numeric = TRUE; break; case 'q': opt_quiet = TRUE; break; case 'I': strncpy (ifname, optarg, 1024); break; case 'h': return -1; case 'p': dport = atoi(optarg); break; case 't': src_ttl = atoi(optarg); break; case 'F': tcp_th_flags |= TH_FIN; break; case 'S': tcp_th_flags |= TH_SYN; break; case 'R': tcp_th_flags |= TH_RST; break; case 'P': tcp_th_flags |= TH_PUSH; break; case 'A': tcp_th_flags |= TH_ACK; break; case 'U': tcp_th_flags |= TH_URG; break; case 'f': fragmentation = TRUE; break; } }

/* force some conditions */

if (tcp_th_flags == 0) /* tcp flags ain't set */ tcp_th_flags |= TH_FIN; /* default it's FIN */

if (count <= 0 && count != -1) { printf("[parse_options] count must > 0\n"); exit(1); }

if (sending_wait <= 0) { printf("[prase_options] bad timing interval\n"); exit(1); } return 1; }

int get_if_name(void) { int fd; struct ifconf ifc; struct ifreq ibuf[16], ifr, *ifrp, *ifend; struct sockaddr_in sa;

if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("[get_if_name] socket()"); return -1; }

bzero((void*)ibuf, sizeof(ibuf)); /* reset buffer */ ifc.ifc_len = sizeof ibuf; /* set buffer size... */ ifc.ifc_buf = (caddr_t) ibuf; /* and buffer pointer */

/* gets interfaces list */ if ( ioctl(fd, SIOCGIFCONF, (char*)&ifc) == -1 || ifc.ifc_len < sizeof(struct ifreq) ) { perror("[get_if_name] ioctl()"); return -1; }

/* ifrp points to buffer and ifend points to buffer's end */ ifrp = ibuf; ifend = (struct ifreq*) ((char*)ibuf + ifc.ifc_len);

for (; ifrp < ifend; ifrp++) { strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));

if ( ioctl(fd, SIOCGIFFLAGS, (char*)&ifr) == -1) { perror("[get_if_name] ioctl()"); return -1; }

if ( !(ifr.ifr_flags & IFF_UP) ) continue; /* if is down */ if ( strstr(ifr.ifr_name, "lo") ) continue; /* loopback */ if ( ifname[0] != '\0' ) /* opt -I set */ if ( !strstr(ifr.ifr_name, ifname) ) /* don't match */ continue;

/* interface found */ strncpy(ifname, ifr.ifr_name, 1024); memcpy(&sa, &(ifrp->ifr_addr), sizeof(struct sockaddr_in)); strncpy(ifstraddr, inet_ntoa(sa.sin_addr), 1024); return 0; } /* interface not found, use 'lo' */ strncpy(ifname, "lo", 1024); strncpy(ifstraddr, "127.0.0.1", 1024); return 0; }

int get_linkhdrsize(char *ifname) { if ( strstr(ifname, "ppp") ) { linkhdr_size = PPPHDR_SIZE; return 0; } else if ( strstr(ifname, "eth") ) { linkhdr_size = ETHHDR_SIZE; return 0; } else if ( strstr(ifname, "lo") ) { linkhdr_size = LOHDR_SIZE; return 0; } else return 1; }

int open_sockraw() { int s;

s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (s == -1) { perror("[open_sockraw] socket()"); return -1; }

return s; }

int open_sockpacket() /* set promiscuose mode for future use */ { int s; struct ifreq ifr;

s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP)); if (s == -1) { perror("[open_sockpacket] socket()"); return -1; }

strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if ( ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { /* get interface flags */ perror("[open_sockpacket] ioctl()"); return -1; } ifr.ifr_flags |= IFF_PROMISC; /* set promiscuose mode */ if ( ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { /* set interface flags */ perror("[open_sockpacket] ioctl()"); return -1; }

return s; }

int close_sockpacket(int s) { struct ifreq ifr;

strncpy(ifr.ifr_name, ifname, IFNAMSIZ); if ( ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { /* get interface flags */ perror("[open_sockpacket] ioctl()"); return -1; } ifr.ifr_flags ^= IFF_PROMISC; /* unset promiscuose mode */ if ( ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { /* set interface flags */ perror("[open_sockpacket] ioctl()"); return -1; }

return close(s); }

void resolver (struct sockaddr * addr, char *hostname) { struct sockaddr_in *address; struct hostent *host;

address = (struct sockaddr_in *)addr;

bzero((char *)address, sizeof(struct sockaddr_in)); address->sin_family = AF_INET; address->sin_addr.s_addr = inet_addr(hostname);

if ( (int)address->sin_addr.s_addr == -1) { host = gethostbyname(hostname); if (host) { bcopy( host->h_addr, (char *)&address->sin_addr,host->h_length); } else { perror("Could not resolve address"); exit(1); } } }

void ip_sender (char* src, char* dst, char *data, unsigned int datalen, int more_fragments, unsigned short fragoff) { char *packet; int result, packetsize; struct iphdr *ip;

packetsize = sizeof(struct iphdr) + datalen; if ( (packet = malloc(packetsize)) == NULL) { perror("[ip_sender] malloc()"); return; } ip = (struct iphdr*) packet;

bzero(packet, packetsize); /* copy src and dst address */ bcopy(src, &ip->saddr, sizeof(ip->saddr)); bcopy(dst, &ip->daddr, sizeof(ip->daddr));

/* ip header */ ip->version = 4; ip->ihl = sizeof(struct iphdr)/4; ip->tos = 0; ip->tot_len = htons(packetsize); ip->id = htons(getpid() & 255); ip->frag_off |= htons(more_fragments); ip->frag_off |= htons(fragoff >> 3); /* shift three flags bit */ ip->ttl = src_ttl; ip->protocol = 6; /* tcp */ ip->check = 0; /* always computed by the kernel */

/* copies data */ bcopy(data, packet+sizeof(struct iphdr), datalen);

result = sendto(sockraw, packet, packetsize, 0, (struct sockaddr*)&remote, sizeof(remote));

if (result == -1 && errno != EINTR) { perror("[ip_sender] sendto()"); close(sockraw); close_sockpacket(sockpacket); exit(1); } free(packet); }

void sendfin (int signal_id) { int tcphdr_size; char *packet_tcphdr; struct tcphdr *tcp; struct tcp_pseudohdr { struct in_addr saddr; struct in_addr daddr; u_char zero; u_char protocol; u_short lenght; struct tcphdr tcpheader; } pseudoheader;

tcphdr_size = sizeof(struct tcphdr); if ( (packet_tcphdr = malloc(tcphdr_size)) == NULL) { perror("[sendfin] malloc()"); return; } tcp = (struct tcphdr*) packet_tcphdr;

signal(SIGALRM, sendfin); bzero(packet_tcphdr, tcphdr_size);

/* tcp header */ tcp->th_dport = htons(dport); tcp->th_sport = htons(sport); tcp->th_seq = htonl(rand()); tcp->th_ack = htonl(0); tcp->th_off = sizeof(struct tcphdr)/4; tcp->th_win = htons(512); tcp->th_flags = tcp_th_flags;

/* compute checksum */ bzero(&pseudoheader, 12+sizeof(struct tcphdr)); pseudoheader.saddr.s_addr = local.sin_addr.s_addr; pseudoheader.daddr.s_addr = remote.sin_addr.s_addr; pseudoheader.protocol = 6; /* tcp */ pseudoheader.lenght = htons(sizeof(struct tcphdr)); bcopy((char*) tcp, (char*) &pseudoheader.tcpheader, sizeof(struct tcphdr)); tcp->th_sum = cksum((u_short*) &pseudoheader, 12+sizeof(struct tcphdr));

if (!fragmentation) { ip_sender((char*)&local.sin_addr,(char*)&remote.sin_addr, packet_tcphdr, tcphdr_size, NO_MORE_FRAGMENTS, 0); } else { ip_sender((char*)&local.sin_addr,(char*)&remote.sin_addr, packet_tcphdr, 16, MORE_FRAGMENTS, 0); ip_sender((char*)&local.sin_addr,(char*)&remote.sin_addr, packet_tcphdr+16, 4, NO_MORE_FRAGMENTS, 16); }

/* adds this fin in delaytable */ delaytable[delaytable_index % 20].seq = sport - initsport; delaytable[delaytable_index % 20].sec = time(NULL); delaytable[delaytable_index % 20].usec = get_utime(); delaytable_index++; /* inc. index */

finsent++; /* inc. sent fin counter */

if (count != -1 && count == finsent) /* count reached */ print_statistics(0);

alarm(sending_wait); sport++; /* inc. source port */ }

/* this isn't a good general checksum algorithm, but i don't need to pad tcp's segments, so it's good for me. */ u_short cksum(u_short *buf, int nwords) { unsigned long sum; u_short *w = buf;

for (sum = 0; nwords > 0; nwords-=2) sum += *w++;

sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; }

void waitresets(void) { char packet[LINK_PACKETSIZE+16], recvflags[1024]; struct iphdr *ip = (struct iphdr*) (packet + ABS_OFFSETIP); struct tcphdr *tcp = (struct tcphdr*) (packet + ABS_OFFSETTCP); struct icmphdr *icmp = (struct icmphdr*) (packet + ABS_OFFSETICMP); struct iphdr *icmp_iph = (struct iphdr*) (packet + ABS_OFFSETICMP + 8);

bzero((void*)packet, sizeof(packet));

while(1) { char src_addr[1024], dst_addr[1024]; int src_port, dst_port, size, rstseq, winsize, sec_delay, usec_delay; float ms_delay; struct in_addr src, dst;

size = recv(sockpacket, &packet, LINK_PACKETSIZE+16, 0); if (size == -1 && errno != EINTR) print_statistics(-1); bcopy( &(ip->saddr), &src, sizeof(struct in_addr) ); bcopy( &(ip->daddr), &dst, sizeof(struct in_addr) ); strncpy(src_addr, inet_ntoa(src), 1024); strncpy(dst_addr, inet_ntoa(dst), 1024); src_port = ntohs(tcp->th_sport); dst_port = ntohs(tcp->th_dport);

if ( ip->protocol == IPPROTO_TCP && !memcmp(&ip->saddr, &remote.sin_addr, sizeof(ip->saddr)) && !memcmp(&ip->daddr, &local.sin_addr, sizeof(ip->daddr)) && src_port == dport ) { int i, fin_tablepos = -1;

rstseq = dst_port - initsport; winsize = ntohs(tcp->th_win); recvflags[0] = '\0'; if (tcp->th_flags & TH_RST) strcat(recvflags, "R"); if (tcp->th_flags & TH_SYN) strcat(recvflags, "S"); if (tcp->th_flags & TH_ACK) strcat(recvflags, "A"); if (tcp->th_flags & TH_FIN) strcat(recvflags, "F"); if (tcp->th_flags & TH_PUSH) strcat(recvflags, "P"); if (tcp->th_flags & TH_URG) strcat(recvflags, "U");

for (i=0; i<20; i++) if (delaytable[i].seq == rstseq) { fin_tablepos = i; break; } if (fin_tablepos != -1) { sec_delay = time(NULL) - delaytable[fin_tablepos].sec; usec_delay = get_utime() - delaytable[fin_tablepos].usec; ms_delay = (sec_delay * 1000) + ((float)usec_delay / 1000); } else ms_delay = 0; /* not in table.. */

printf("%d bytes from %s: flags=%s seq=%d ttl=%d win=%d time=%.1f ms\n", size, src_addr, recvflags, rstseq, ip->ttl, winsize, ms_delay); fflush(stdout); rstrecv++; }

if ( ip->protocol == IPPROTO_ICMP ) { if ( icmp->type == 3 && /* Dest. Unreachable */ !memcmp(&icmp_iph->daddr, &remote.sin_addr, sizeof(ip->daddr)) && !memcmp(&ip->daddr, &local.sin_addr, sizeof(ip->daddr)) ) icmpunreach_log(src_addr, icmp->code);

else if (icmp->type == 11 && /* Time exceeded */ !memcmp(&icmp_iph->daddr, &remote.sin_addr, sizeof(ip->daddr)) && !memcmp(&ip->daddr, &local.sin_addr, sizeof(ip->daddr)) ) icmptimeexc_log(src_addr, icmp->code); } } }

void icmptimeexc_log(char *src_addr, unsigned short icmp_code) { switch(icmp_code) { case ICMP_EXC_TTL: printf("TTL 0 during transit from %s\n", src_addr); break; case ICMP_EXC_FRAGTIME: printf("TTL 0 during reassembly from %s\n", src_addr); } }

void icmpunreach_log(char *src_addr, unsigned short icmp_code) { switch(icmp_code) { case ICMP_HOST_UNREACH: printf("Host Unreachable from %s\n", src_addr); break; case ICMP_PORT_UNREACH: printf("Port Unreachable from %s\n", src_addr); break; default: printf("ICMP Unreachable type %d from %s\n", icmp_code, src_addr); break; } }

void print_statistics(int signal_id) { unsigned int lossrate;

close_sockpacket(sockpacket);

if (rstrecv > 0) lossrate = 100 - ((rstrecv*100)/finsent); else if (!finsent) lossrate = 0; /* no packets sent, no packets loss... */ else lossrate = 100; /* packets sent... nadaz returned */

printf("\n--- %s hping statistic ---\n", targetname); printf("%d packets tramitted, %d packets received, %d%% packet loss\n", finsent, rstrecv, lossrate); exit(0); };

void usage(void) { int index = 0; char *helpdata[] = { "usage: hping host [options]\n", "\tc - packets count\n", "\ti - wait\n" "\tn - numeric output\n", "\tq - quiet\n", "\tI - interface name\n", "\tp - destination port (default 0)\n", "\tt - ttl (default 64)\n", "\th - shows this help\n", "\tF - set FIN flag\n", "\tS - set SYN flag\n", "\tR - set RST flag\n", "\tP - set PUSH flag\n", "\tA - set ACK flag\n", "\tU - set URG flag\n", "\tf - splits packets in two fragments\n", NULL };

while (helpdata[index]) { printf(helpdata[index]); ++index; } exit(0); };

long get_utime(void) { struct timeval tmptv;

gettimeofday(&tmptv, NULL); return tmptv.tv_usec; }

--wac7ysb48OaltWcw--

-- end of forwarded message --

-- 
С тем, что не помешает никогда,
                                               Kittle