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 57struct protoent *protocol = NULL; 58 59struct packet { 60 struct icmphdr hdr; 61 char msg[PACKETSIZE - sizeof(struct icmphdr)]; 62}; 63 64/* 65* Function Prototypes 66*/ 67int ltp_run_ping_tests(char *hostName); 68int ltp_run_traceroute_tests(char *hostName); 69void ping_network(struct sockaddr_in *rawAddr, int pid); 70void output_to_display(void *netPacket, int bytes, int pid); 71unsigned short checksum(void *netPacket, int len); 72int network_listener(char *hostname, int pid); 73void 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********************************************************************/ 84int 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******************************************************************************/ 306int 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***********************************************************************/ 333int 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*******************************************************************************/ 365int 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*****************************************************************/ 412unsigned 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******************************************************************/ 439void 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***********************************************************************/ 483void 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***********************************************************************/ 560void 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