• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- linux-c -*- */
2 /*
3  *
4  *
5  *   Copyright (c) International Business Machines  Corp., 2000
6  *
7  *   This program is free software;  you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15  *   the GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program;  if not, write to the Free Software
19  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  *
21  *
22  */
23 /*
24  * ltpClient.c
25  *
26  * LTP Network Socket Test Client
27  *
28  *
29  */
30 
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/ip_icmp.h>
35 #include <arpa/inet.h>
36 #include <netdb.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <resolv.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <sys/time.h>
45 
46 #define LOCAL_UDP_SERVER_PORT   10000
47 #define LOCAL_TCP_SERVER_PORT   10001
48 #define LOCAL_MCAST_SERVER_PORT 10002
49 #define MAX_MSG_LEN             256
50 #define TIMETOLIVE              10
51 #define PACKETSIZE	            64
52 #define NET_ERROR               -1
53 #define PACKET_LEN              1024	/* 1K should be plenty */
54 #define TRUE                    1
55 #define FALSE                   0
56 
57 struct protoent *protocol = NULL;
58 
59 struct packet {
60 	struct icmphdr hdr;
61 	char msg[PACKETSIZE - sizeof(struct icmphdr)];
62 };
63 
64 /*
65 *   Function Prototypes
66 */
67 int ltp_run_ping_tests(char *hostName);
68 int ltp_run_traceroute_tests(char *hostName);
69 void ping_network(struct sockaddr_in *rawAddr, int pid);
70 void output_to_display(void *netPacket, int bytes, int pid);
71 unsigned short checksum(void *netPacket, int len);
72 int network_listener(char *hostname, int pid);
73 void ltp_traceroute(struct sockaddr_in *rawTraceAddr, char *hostName, int pid);
74 
75 /*******************************************************************
76 *  Function: Main
77 *
78 *  Main will run the tests in this order.
79 *       UDP, TCP and Multicast will be run first, if multicast is enabled.
80 *       If multicast is not enabled, the UDP/TCP tests will continue.
81 *       Once those tests complete, the ping and then traceroute tests will run.
82 *
83 ********************************************************************/
main(int argc,char * argv[])84 int main(int argc, char *argv[])
85 {
86 
87 	int udpSocketHandle, tcpSocketHandle, mcastSocketHandle, rc, i;
88 
89 	struct sockaddr_in udpClientAddr,
90 	    udpRemoteServerAddr,
91 	    tcpClientAddr,
92 	    tcpRemoteServerAddr, mcastClientAddr, mcastRemoteServerAddr;
93 
94 	struct hostent *hostEntry;
95 
96 	char hostName[MAX_MSG_LEN],
97 	    progName[MAX_MSG_LEN], traceName[MAX_MSG_LEN], multiCast = TRUE;
98 
99 	unsigned char ttl = 1;
100 
101 	mcastSocketHandle = -1;
102 
103 	/* check command line args */
104 	if (argc < 4) {
105 		printf
106 		    ("usage :<server-hostname> <trace-hostName> <data1> ... <dataN> \n");
107 		exit(1);
108 	}
109 
110 	strncpy(progName, argv[0], MAX_MSG_LEN);
111 	strncpy(hostName, argv[1], MAX_MSG_LEN);
112 	strncpy(traceName, argv[2], MAX_MSG_LEN);
113 
114 	/* get server IP address (no check if input is IP address or DNS name */
115 	hostEntry = gethostbyname(hostName);
116 
117 	if (hostEntry == NULL) {
118 		printf("%s: unknown host passed'%s' \n", progName, hostName);
119 		exit(1);
120 	}
121 
122 	printf("%s: sending data to '%s' (IP : %s) \n", progName,
123 	       hostEntry->h_name,
124 	       inet_ntoa(*(struct in_addr *)hostEntry->h_addr_list[0]));
125 
126 	/* Setup UDP data packets */
127 
128 	udpRemoteServerAddr.sin_family = hostEntry->h_addrtype;
129 	memcpy((char *)&udpRemoteServerAddr.sin_addr.s_addr,
130 	       hostEntry->h_addr_list[0], hostEntry->h_length);
131 	udpRemoteServerAddr.sin_port = htons(LOCAL_UDP_SERVER_PORT);
132 
133 	/* Setup TCP data packets */
134 
135 	tcpRemoteServerAddr.sin_family = hostEntry->h_addrtype;
136 	memcpy((char *)&tcpRemoteServerAddr.sin_addr.s_addr,
137 	       hostEntry->h_addr_list[0], hostEntry->h_length);
138 	tcpRemoteServerAddr.sin_port = htons(LOCAL_TCP_SERVER_PORT);
139 
140 	/* Setup multiCast data packets */
141 
142 	mcastRemoteServerAddr.sin_family = hostEntry->h_addrtype;
143 	memcpy((char *)&mcastRemoteServerAddr.sin_addr.s_addr,
144 	       hostEntry->h_addr_list[0], hostEntry->h_length);
145 	mcastRemoteServerAddr.sin_port = htons(LOCAL_MCAST_SERVER_PORT);
146 
147 	/* socket creation */
148 	udpSocketHandle = socket(AF_INET, SOCK_DGRAM, 0);
149 	tcpSocketHandle = socket(AF_INET, SOCK_STREAM, 0);
150 
151 	if (udpSocketHandle < 0) {
152 		printf("%s: Error: cannot open UDP socket \n", progName);
153 	}
154 
155 	if (tcpSocketHandle < 0) {
156 		printf("%s: Error: cannot open TCP socket \n", progName);
157 	}
158 
159 	/* bind any UDP port */
160 	udpClientAddr.sin_family = AF_INET;
161 	udpClientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
162 	udpClientAddr.sin_port = htons(0);
163 
164 	/* bind any TCP port */
165 	tcpClientAddr.sin_family = AF_INET;
166 	tcpClientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
167 	tcpClientAddr.sin_port = htons(0);
168 
169 	if (udpSocketHandle > 0) {
170 		rc = bind(udpSocketHandle, (struct sockaddr *)&udpClientAddr,
171 			  sizeof(udpClientAddr));
172 
173 		if (rc < 0) {
174 			printf("%s: Error: cannot bind UDP port\n", progName);
175 		}
176 	}
177 
178 	if (tcpSocketHandle > 0) {
179 		rc = bind(tcpSocketHandle, (struct sockaddr *)&tcpClientAddr,
180 			  sizeof(tcpClientAddr));
181 
182 		if (rc < 0) {
183 			printf("%s: Error: cannot bind TCP port\n", progName);
184 		} else {
185 			/* connect to server */
186 			rc = connect(tcpSocketHandle,
187 				     (struct sockaddr *)&tcpRemoteServerAddr,
188 				     sizeof(tcpRemoteServerAddr));
189 
190 			if (rc < 0) {
191 				printf
192 				    ("Error: cannot connect tp TCP Server \n");
193 			}
194 		}
195 	}
196 
197 	/* check given address is multicast */
198 	if (!IN_MULTICAST(ntohl(mcastRemoteServerAddr.sin_addr.s_addr))) {
199 		printf
200 		    ("%s : Hostname [%s] passed [%s] is not a multicast server\n",
201 		     progName, hostName,
202 		     inet_ntoa(mcastRemoteServerAddr.sin_addr));
203 		printf("The multiCast Server will not be started \n");
204 		multiCast = FALSE;
205 	} else {
206 		/* create socket */
207 		mcastSocketHandle = socket(AF_INET, SOCK_DGRAM, 0);
208 		if (mcastSocketHandle < 0) {
209 			printf("Error: %s : cannot open mulitCast socket\n",
210 			       progName);
211 			multiCast = FALSE;
212 		}
213 
214 		/* bind any port number */
215 		mcastClientAddr.sin_family = AF_INET;
216 		mcastClientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
217 		mcastClientAddr.sin_port = htons(0);
218 
219 		if (bind
220 		    (mcastSocketHandle, (struct sockaddr *)&mcastClientAddr,
221 		     sizeof(mcastClientAddr)) < 0) {
222 			printf("Error: binding multiCast socket");
223 			multiCast = FALSE;
224 		}
225 
226 		if (setsockopt
227 		    (mcastSocketHandle, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
228 		     sizeof(ttl)) < 0) {
229 			printf("Error: %s : cannot set ttl = %d \n", progName,
230 			       ttl);
231 			multiCast = FALSE;
232 		}
233 
234 		printf("%s : sending data on multicast group '%s' (%s)\n",
235 		       progName, hostEntry->h_name,
236 		       inet_ntoa(*(struct in_addr *)hostEntry->h_addr_list[0]));
237 
238 	}
239 
240 	/* Skip over the program and hostnames and just send data */
241 	for (i = 3; i < argc; i++) {
242 
243 		if (udpSocketHandle > 0) {
244 			rc = sendto(udpSocketHandle, argv[i],
245 				    strlen(argv[i]) + 1, 0,
246 				    (struct sockaddr *)&udpRemoteServerAddr,
247 				    sizeof(udpRemoteServerAddr));
248 
249 			if (rc < 0) {
250 				printf("%s: cannot send UDP data %d \n",
251 				       progName, i - 1);
252 				close(udpSocketHandle);
253 			} else {
254 				printf("%s: UDP data%u sent (%s)\n", progName,
255 				       i - 1, argv[i]);
256 			}
257 		} else {
258 			printf("%s UDP Socket not open for send \n", hostName);
259 		}
260 
261 		if (tcpSocketHandle > 0) {
262 			rc = send(tcpSocketHandle, argv[i], strlen(argv[i]) + 1,
263 				  0);
264 
265 			if (rc < 0) {
266 				printf("cannot send TCP data ");
267 				close(tcpSocketHandle);
268 
269 			} else {
270 				printf("%s: TCP data%u sent (%s)\n", progName,
271 				       i - 1, argv[i]);
272 			}
273 		} else {
274 			printf("%s TCP Socket not open for send \n", hostName);
275 		}
276 
277 		if (multiCast) {
278 			rc = sendto(mcastSocketHandle, argv[i],
279 				    strlen(argv[i]) + 1, 0,
280 				    (struct sockaddr *)&mcastRemoteServerAddr,
281 				    sizeof(mcastRemoteServerAddr));
282 
283 			if (rc < 0) {
284 				printf("%s : cannot send multiCast data %d\n",
285 				       progName, i - 1);
286 				close(mcastSocketHandle);
287 				multiCast = FALSE;
288 			}
289 		}
290 	}
291 
292 	sleep(5);
293 
294 	ltp_run_traceroute_tests(traceName);
295 
296 	ltp_run_ping_tests(hostName);
297 
298 	return 0;
299 
300 }
301 
302 /*****************************************************************************
303 * Function: ltp_run_traceroute_tests - host look up and start traceroute processes
304 *
305 ******************************************************************************/
ltp_run_traceroute_tests(char * hostName)306 int ltp_run_traceroute_tests(char *hostName)
307 {
308 
309 	struct hostent *hostEntry;
310 	struct sockaddr_in rawTraceAddr;
311 	int pid = -1;
312 
313 	pid = getpid();
314 
315 	protocol = getprotobyname("ICMP");
316 	hostEntry = gethostbyname(hostName);
317 
318 	memset(&rawTraceAddr, 0, sizeof(rawTraceAddr));
319 
320 	rawTraceAddr.sin_family = hostEntry->h_addrtype;
321 	rawTraceAddr.sin_port = 0;
322 	rawTraceAddr.sin_addr.s_addr = *(long *)hostEntry->h_addr;
323 
324 	ltp_traceroute(&rawTraceAddr, hostName, pid);
325 
326 	return 0;
327 }
328 
329 /**********************************************************************
330 * Function: ltp_run_ping_tests - host look up and start ping processes
331 *
332 ***********************************************************************/
ltp_run_ping_tests(char * hostName)333 int ltp_run_ping_tests(char *hostName)
334 {
335 
336 	struct hostent *hostEntry;
337 	struct sockaddr_in rawAddr;
338 	int pid = -1;
339 
340 	pid = getpid();
341 
342 	protocol = getprotobyname("ICMP");
343 	hostEntry = gethostbyname(hostName);
344 
345 	memset(&rawAddr, 0, sizeof(rawAddr));
346 
347 	rawAddr.sin_family = hostEntry->h_addrtype;
348 	rawAddr.sin_port = 0;
349 	rawAddr.sin_addr.s_addr = *(long *)hostEntry->h_addr;
350 
351 	if (fork() == 0) {
352 		network_listener(hostName, pid);
353 	} else {
354 		ping_network(&rawAddr, pid);
355 
356 	}
357 
358 	return 0;
359 }
360 
361 /******************************************************************************
362 * Function: network_listener - separate process to listen for and collect messages
363 *
364 *******************************************************************************/
network_listener(char * hostName,int pid)365 int network_listener(char *hostName, int pid)
366 {
367 
368 	int rawSocket, count, value = TIMETOLIVE;
369 	struct sockaddr_in rawAddr;
370 	unsigned char packet[PACKET_LEN];
371 
372 	rawSocket = socket(PF_INET, SOCK_RAW, protocol->p_proto);
373 	count = 0;
374 
375 	if (rawSocket < 0) {
376 		printf("%s: Error: cannot open RAW socket \n", hostName);
377 		return (NET_ERROR);
378 	}
379 
380 	while (1) {		/* loop forever */
381 
382 		int bytes;
383 		socklen_t len = sizeof(rawAddr);
384 
385 		memset(packet, 0, sizeof(packet));
386 
387 		bytes =
388 		    recvfrom(rawSocket, packet, sizeof(packet), 0,
389 			     (struct sockaddr *)&rawAddr, &len);
390 
391 		if (bytes > 0)
392 			output_to_display(packet, bytes, pid);
393 		else {
394 			printf("%s : cannot receive data\n", hostName);
395 			break;
396 		}
397 		count++;
398 
399 		if (value == count) {
400 			printf("Exiting the network_listener...\n");
401 		}
402 	}
403 
404 	close(rawSocket);
405 	return (0);
406 }
407 
408 /****************************************************************
409 * Function: checksum - standard 1s complement checksum
410 *
411 *****************************************************************/
checksum(void * netPacket,int len)412 unsigned short checksum(void *netPacket, int len)
413 {
414 
415 	unsigned short *packetPtr = netPacket, result;
416 
417 	unsigned int sum = 0;
418 
419 	for (sum = 0; len > 1; len -= 2) {
420 		sum += *packetPtr++;
421 	}
422 
423 	if (len == 1) {
424 		sum += *(unsigned char *)packetPtr;
425 	}
426 
427 	sum = (sum >> 16) + (sum & 0xFFFF);
428 	sum += (sum >> 16);
429 
430 	result = ~sum;
431 
432 	return result;
433 }
434 
435 /*****************************************************************
436 * Function: output_to_display - Output to display info. from the
437 *                               listener
438 ******************************************************************/
output_to_display(void * netPacket,int bytes,int pid)439 void output_to_display(void *netPacket, int bytes, int pid)
440 {
441 
442 	int i;
443 	struct iphdr *ip = netPacket;
444 	struct icmphdr *icmpPtr = netPacket + ip->ihl * 4;
445 	struct in_addr tmp_addr;
446 
447 	printf
448 	    ("\n************** -- Ping Tests - **********************************************\n");
449 
450 	for (i = 0; i < bytes; i++) {
451 		if (!(i & 15)) {
452 			printf("\n[%d]:  ", i);
453 		}
454 
455 		printf("[%d] ", ((unsigned char *)netPacket)[i]);
456 	}
457 
458 	printf("\n");
459 
460 	tmp_addr.s_addr = ip->saddr;
461 
462 	printf("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d src=%s ",
463 	       ip->version, ip->ihl * 4, ntohs(ip->tot_len), ip->protocol,
464 	       ip->ttl, inet_ntoa(tmp_addr));
465 
466 	tmp_addr.s_addr = ip->daddr;
467 	printf("dst=%s\n", inet_ntoa(tmp_addr));
468 
469 	if (icmpPtr->un.echo.id == pid) {
470 
471 		printf("ICMP: type[%d/%d] checksum[%d] id[%d] seq[%d]\n\n",
472 		       icmpPtr->type, icmpPtr->code, ntohs(icmpPtr->checksum),
473 		       icmpPtr->un.echo.id, icmpPtr->un.echo.sequence);
474 
475 	}
476 }
477 
478 /***********************************************************************
479 * Function: ping_network - Build a message and send it.
480 *
481 *
482 ***********************************************************************/
ping_network(struct sockaddr_in * rawAddr,int pid)483 void ping_network(struct sockaddr_in *rawAddr, int pid)
484 {
485 
486 	const int value = TIMETOLIVE;
487 	int i, rawSocket, count = 1;
488 
489 	struct packet rawPacket;
490 
491 	struct sockaddr_in r_addr;
492 
493 	rawSocket = socket(PF_INET, SOCK_RAW, protocol->p_proto);
494 
495 	if (rawSocket < 0) {
496 		printf("Error: cannot open RAW socket %d\n", rawSocket);
497 		return;
498 	}
499 
500 	if (setsockopt(rawSocket, SOL_IP, IP_TTL, &value, sizeof(value)) != 0) {
501 		printf("ERROR: Setting TimeToLive option");
502 	} else {
503 		printf
504 		    ("The test will run for [%d] iterations -- Ctrl-C to interupt \n",
505 		     value);
506 		sleep(3);
507 	}
508 
509 	if (fcntl(rawSocket, F_SETFL, O_NONBLOCK) != 0) {
510 		printf("ERROR: Failed request nonblocking I/O");
511 	}
512 
513 	while (1) {
514 
515 		socklen_t msgLength = sizeof(r_addr);
516 
517 		printf("Message ID #:%d \n", count);
518 
519 		if (recvfrom
520 		    (rawSocket, &rawPacket, sizeof(rawPacket), 0,
521 		     (struct sockaddr *)&r_addr, &msgLength) > 0) {
522 			printf("*** -- Message Received -- ***\n");
523 		}
524 
525 		memset(&rawPacket, 0, sizeof(rawPacket));
526 
527 		rawPacket.hdr.type = ICMP_ECHO;
528 		rawPacket.hdr.un.echo.id = pid;
529 
530 		for (i = 0; i < sizeof(rawPacket.msg) - 1; i++) {
531 			rawPacket.msg[i] = i + '0';
532 		}
533 
534 		rawPacket.msg[i] = 0;
535 		rawPacket.hdr.un.echo.sequence = count++;
536 		rawPacket.hdr.checksum =
537 		    checksum(&rawPacket, sizeof(rawPacket));
538 
539 		if (sendto
540 		    (rawSocket, &rawPacket, sizeof(rawPacket), 0,
541 		     (struct sockaddr *)rawAddr, sizeof(*rawAddr)) <= 0)
542 			printf("ERROR: sendto failed !!");
543 
544 		sleep(1);
545 
546 		if (value == count) {
547 			printf("Exiting ping test...\n");
548 			break;
549 		}
550 	}
551 
552 	close(rawSocket);
553 }
554 
555 /**********************************************************************
556 *  Function: ltp_traceroute
557 *                      try to reach the destination
558 *                      while outputting hops along the route
559 ***********************************************************************/
ltp_traceroute(struct sockaddr_in * rawTraceAddr,char * hostName,int pid)560 void ltp_traceroute(struct sockaddr_in *rawTraceAddr, char *hostName, int pid)
561 {
562 
563 	const int flag = TRUE;
564 	int TimeToLive = 0;
565 	int i, rawTraceSocket, count = 1;
566 	socklen_t length;
567 	struct packet rawTracePacket;
568 	unsigned char tracePacket[PACKET_LEN];
569 	struct sockaddr_in rawReceiveAddr;
570 	struct hostent *hostEntry2;
571 	struct in_addr tmp_addr;
572 
573 	printf
574 	    ("\n************** -- Trace Route Tests - **********************************************\n");
575 
576 	rawTraceSocket = socket(PF_INET, SOCK_RAW, protocol->p_proto);
577 
578 	if (rawTraceSocket < 0) {
579 		printf("Error: cannot open RAW socket %d\n", rawTraceSocket);
580 		return;
581 	}
582 
583 	if (setsockopt(rawTraceSocket, SOL_IP, SO_ERROR, &flag, sizeof(flag)) !=
584 	    0)
585 		printf("ERROR: Setting socket options");
586 
587 	do {
588 		struct iphdr *ip;
589 		length = sizeof(rawReceiveAddr);
590 
591 		TimeToLive++;
592 		if (setsockopt
593 		    (rawTraceSocket, SOL_IP, IP_TTL, &TimeToLive,
594 		     sizeof(TimeToLive)) != 0) {
595 			printf("ERROR: Setting TimeToLive option");
596 		}
597 
598 		memset(&rawTracePacket, 0, sizeof(rawTracePacket));
599 
600 		rawTracePacket.hdr.type = ICMP_ECHO;
601 		rawTracePacket.hdr.un.echo.id = pid;
602 
603 		for (i = 0; i < sizeof(rawTracePacket.msg) - 1; i++) {
604 			rawTracePacket.msg[i] = i + '0';
605 		}
606 
607 		rawTracePacket.msg[i] = 0;
608 		rawTracePacket.hdr.un.echo.sequence = count++;
609 		rawTracePacket.hdr.checksum =
610 		    checksum(&rawTracePacket, sizeof(rawTracePacket));
611 
612 		if (sendto
613 		    (rawTraceSocket, &rawTracePacket, sizeof(rawTracePacket), 0,
614 		     (struct sockaddr *)rawTraceAddr,
615 		     sizeof(*rawTraceAddr)) <= 0) {
616 			printf("ERROR: sendto failed !!");
617 		}
618 		sleep(1);
619 
620 		if (recvfrom
621 		    (rawTraceSocket, tracePacket, sizeof(tracePacket),
622 		     MSG_DONTWAIT, (struct sockaddr *)&rawReceiveAddr,
623 		     &length) > 0) {
624 			ip = (void *)tracePacket;
625 
626 			tmp_addr.s_addr = ip->saddr;
627 			printf("Host IP:#%d: %s \n", count - 1,
628 			       inet_ntoa(tmp_addr));
629 
630 			hostEntry2 =
631 			    gethostbyaddr((void *)&rawReceiveAddr, length,
632 					  rawReceiveAddr.sin_family);
633 
634 			if (hostEntry2 != NULL)
635 				printf("(%s)\n", hostEntry2->h_name);
636 			else
637 				perror("Name: ");
638 		} else {
639 			printf("%s : data send complete...\n", hostName);
640 			break;
641 		}
642 
643 	}
644 	while (rawReceiveAddr.sin_addr.s_addr != rawTraceAddr->sin_addr.s_addr);
645 
646 	printf
647 	    ("\n************** -- End Trace Route Tests - ******************************************\n");
648 
649 	close(rawTraceSocket);
650 }
651