función Ping() para Harbour/xHarbour
Posted: Thu Apr 22, 2010 7:11 pm
Basada en el código de http://cboard.cprogramming.com/networki ... ogram.html:
Code: Select all
#include "FiveLinux.ch"
function Main()
MsgInfo( Ping( "192.168.0.22" ) )
return nil
#pragma BEGINDUMP
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <string.h>
#include <unistd.h>
char dst_addr[20];
char src_addr[20];
static unsigned short in_cksum(unsigned short *, int);
static void parse_argvs(char**, char*, char* );
static void usage();
static char* getip();
static char* toip(char*);
HB_FUNC( PING )
{
struct iphdr* ip;
struct iphdr* ip_reply;
struct icmphdr* icmp;
struct sockaddr_in connection;
char* packet;
char* buffer;
int sockfd;
int optval;
int addrlen;
int siz;
/*
if (getuid() != 0)
{
fprintf(stderr, "%s: root privelidges needed\n", *(argv + 0));
exit(EXIT_FAILURE);
}
*/
// parse_argvs(argv, dst_addr, src_addr);
strncpy( dst_addr, toip( ( char * ) hb_parc( 1 ) ), 20 );
strncpy( src_addr, toip( getip() ), 20 );
// printf("Source address: %s\n", src_addr);
// printf("Destination address: %s\n", dst_addr);
/*
* allocate all necessary memory
*/
packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
/****************************************************************/
ip = (struct iphdr*) packet;
icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));
/*
* here the ip packet is set up
*/
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);
ip->id = htons(0);
ip->frag_off = 0;
ip->ttl = 64;
ip->protocol = IPPROTO_ICMP;
ip->saddr = inet_addr(src_addr);
ip->daddr = inet_addr(dst_addr);
ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
{
hb_retl( FALSE );
return;
// perror("socket");
// exit(EXIT_FAILURE);
}
/*
* IP_HDRINCL must be set on the socket so that
* the kernel does not attempt to automatically add
* a default ip header to the packet
*/
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
/*
* here the icmp packet is created
* also the ip checksum is generated
*/
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->un.echo.id = random();
icmp->un.echo.sequence = 0;
icmp-> checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
connection.sin_family = AF_INET;
connection.sin_addr.s_addr = inet_addr(dst_addr);
/*
* now the packet is sent
*/
sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr*)&connection, sizeof(struct sockaddr));
// printf("Sent %d byte packet to %s\n", ip->tot_len, dst_addr);
/*
* now we listen for responses
*/
addrlen = sizeof(connection);
if (( siz = recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen)) == -1)
{
hb_retl( FALSE );
// perror("recv");
}
else
{
hb_retl( TRUE );
// printf("Received %d byte reply from %s:\n", siz , dst_addr);
// ip_reply = (struct iphdr*) buffer;
// printf("ID: %d\n", ntohs(ip_reply->id));
// printf("TTL: %d\n", ip_reply->ttl);
}
free(packet);
free(buffer);
close(sockfd);
// return 0;
}
static void parse_argvs(char** argv, char* dst, char* src)
{
int i;
if(!(*(argv + 1)))
{
/* there are no options on the command line */
usage();
exit(EXIT_FAILURE);
}
if (*(argv + 1) && (!(*(argv + 2))))
{
/*
* only one argument provided
* assume it is the destination server
* source address is local host
*/
strncpy(dst, *(argv + 1), 15);
strncpy(src, getip(), 15);
return;
}
else if ((*(argv + 1) && (*(argv + 2))))
{
/*
* both the destination and source address are defined
* for now only implemented is a source address and
* destination address
*/
strncpy(dst, *(argv + 1), 15);
i = 2;
while(*(argv + i + 1))
{
if (strncmp(*(argv + i), "-s", 2) == 0)
{
strncpy(src, *(argv + i + 1), 15);
break;
}
i++;
}
}
}
static void usage()
{
fprintf(stderr, "\nUsage: pinger [destination] <-s [source]>\n");
fprintf(stderr, "Destination must be provided\n");
fprintf(stderr, "Source is optional\n\n");
}
static char* getip()
{
char buffer[256];
struct hostent* h;
gethostname(buffer, 256);
h = gethostbyname(buffer);
return inet_ntoa(*(struct in_addr *)h->h_addr);
}
/*
* return the ip address if host provided by DNS name
*/
static char* toip(char* address)
{
struct hostent* h;
h = gethostbyname(address);
return inet_ntoa(*(struct in_addr *)h->h_addr);
}
/*
* in_cksum --
* Checksum routine for Internet Protocol
* family headers (C Version)
*/
static unsigned short in_cksum(unsigned short *addr, int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1)
{
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
#pragma ENDDUMP