Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабы / 3 / 4.tar / 4 / 4 / net_ping / main

.c
Скачиваний:
22
Добавлен:
17.04.2013
Размер:
4.55 Кб
Скачать
#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/time.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip_icmp.h>

#include <signal.h>

#include <getopt.h>

typedef struct sockaddr SA;

SA *r_addr;
SA *in_addr;
socklen_t r_len;
socklen_t in_len;

#define MAX_LENGTH 65536
char dgram_buf[MAX_LENGTH];
char in_buf[MAX_LENGTH];

int datalen = 56;

int verbose = 0;
#define vprintf if (verbose) printf

int sd = -1; /* socket descriptor */
unsigned short nseq = 0;

int stop = 0;

#include "icmp_strings.h"

double tv_diff(struct timeval *old, struct timeval *new)
{
	return (new->tv_sec - old->tv_sec)*1000 +
					((double)(new->tv_usec - old->tv_usec))/1000;
}

void proc_v4()
{
	struct ip *ip;
	struct icmp *icmp;
	int iplen, icmplen;
	double rtt;

	static char s_addr[128]; /* max UNIX domain */
		
	ssize_t res = recvfrom(sd, in_buf, MAX_LENGTH, 0, in_addr, &in_len);
	if (res <= 0) return;
	
	struct timeval ntv, *tvsend;
	gettimeofday(&ntv, NULL);
	
	ip = (struct ip *)in_buf; /* ip header */
	iplen = ip->ip_hl << 2; /* ip header length = ip_hl / 4 */
	
	icmp = (struct icmp *)(in_buf+iplen); /* icmp header*/
	if ( (icmplen = res - iplen) < 8){
		vprintf("Incomplete icmp packet len=%d\n", icmplen);
		return;
	}
	
	struct sockaddr_in *sin = (struct sockaddr_in*)in_addr;
	inet_ntop(AF_INET, &sin->sin_addr,
			s_addr, sizeof(s_addr));
	
	if (icmp->icmp_type == ICMP_ECHOREPLY){		
		if (ntohs(icmp->icmp_id) != getpid()){
			vprintf("FOREIGN %d bytes from %s: seq=%d ttl=%d\n",
				icmplen, s_addr, ntohs(icmp->icmp_seq), ip->ip_ttl);
			return;
		}
		tvsend = (struct timeval *)icmp->icmp_data;
		rtt = tv_diff(tvsend, &ntv);
		printf("%d bytes from %s: seq=%d ttl=%d rtt=%.3f ms\n",
			icmplen, s_addr, ntohs(icmp->icmp_seq), ip->ip_ttl, rtt);
	}
	else{
		/*if (ntohs(icmp->icmp_id) != getpid()){
			vprintf("Receive %d bytes from %s: type %d, code %d\n",
				icmplen, s_addr, icmp->icmp_type, icmp->icmp_code);
			return;
		}*/
		printf("From %s: %s - %s\n",
			s_addr,
			ICMP_TYPES[icmp->icmp_type],
			ICMP_CODES[icmp->icmp_type][icmp->icmp_code]);
	}
}

unsigned short in_checksum(unsigned short *addr, int len)
{
	int nleft = len;
	int sum = 0;
	unsigned short *w = addr;
	unsigned short answer = 0;
	
	while (nleft > 1){
		sum += *w++;
		nleft -= 2;
	}
	if (nleft == 1){
		*(unsigned char *)(&answer) = *(unsigned char *)w;
		sum += answer;
	}
	
	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	return answer;
}

void send_v4(int sig_num)
{
	int len;
	struct icmp *hdr = (struct icmp *)dgram_buf;
	
	len = 8 + datalen;
	memset(hdr, 0, len);
	
	hdr->icmp_type = ICMP_ECHO;
	hdr->icmp_code = 0;
	hdr->icmp_id =  htons(getpid());
	hdr->icmp_seq = htons(nseq++);
	gettimeofday((struct timeval *)hdr->icmp_data, NULL);
	
	hdr->icmp_cksum = 0;
	hdr->icmp_cksum = in_checksum((u_short *)hdr, len);
	
	sendto(sd, dgram_buf, len, 0, r_addr, r_len);
	alarm(1);
	return;	
}

void sig_int(sig_num)
{
	printf("Catch interrupt\n");
	stop++;
	exit(0);
}

void main_loop()
{
	sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if (sd < 0){
		perror("Create socket"); exit(1);
	}
	
	setuid(getuid());
	
	stop = 0;
	signal(SIGINT, &sig_int);
	signal(SIGALRM, &send_v4);
	kill(getpid(), SIGALRM);
	
	fd_set rset;
	FD_ZERO(&rset);
	FD_SET(sd, &rset);	
	
	printf("Start ping cicle\n");
	while (!stop){
		FD_SET(sd, &rset);
		select(sd+1,&rset,NULL,NULL,NULL);
		if (FD_ISSET(sd, &rset)){
			proc_v4();
		}		
	}
	printf("Finish\n");
}


int main(int argc, char *argv[])
{
	printf("Net_ping program.\n");
	
	char c;
	while ( (c = getopt(argc, argv, "v")) != -1 ){
		switch (c){
			case 'v':
				verbose = 1;
				printf("Running verbose mode\n");
				break;
			case '?':
				fprintf(stderr, "Unrecognised option: %c", c);
				exit(1);
		}
	}

	if (argc < 2){ /* print usage */
		perror("Not enough arguments");
		printf("Usage: %s <remote_ip>\n", argv[0]);
		exit(1);
	}
	const char *remote_ip = argv[argc-1];
	
	printf("Remote machine: %s\n", argv[argc-1]);
	
	in_len = sizeof(struct sockaddr_in);
	in_addr = (struct sockaddr *) malloc(in_len);

	r_len = sizeof(struct sockaddr_in);
	r_addr = (struct sockaddr *) malloc(r_len);
	struct sockaddr_in *t_addr = (struct sockaddr_in *)r_addr;
	
	memset(t_addr, 0, r_len);
	t_addr->sin_family = AF_INET;
	if (inet_pton(AF_INET, remote_ip, &(t_addr->sin_addr))<=0){
		perror("Bad remote_ip address");
		return -1;
	}

	main_loop();		

	free(r_addr);
	free(in_addr);
	return 0;
}
Соседние файлы в папке net_ping