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