📄 nettest.c
字号:
******************************************************************************/int make_sock (test_net, sock_type)int test_net;int sock_type;{ struct protoent *proto; struct sockaddr_in from; int dontblock = 1; int psock = 0; func_name = "make_sock"; TRACE_IN if (!(proto = getprotobyname ("icmp"))) { send_message (-NO_PROTOCOL_ENTRY, FATAL, "%s No protocol entry for ICMP %s", test_name, errmsg (errno)); } if (sock_type == SOCK_DGRAM) { if ((psock = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { send_message (-NO_XMIT_SOCKET, FATAL, "%s socket open failed %s", test_name, errmsg (errno)); } } if (sock_type == SOCK_RAW) { if ((psock = socket (AF_INET, SOCK_RAW, proto->p_proto)) < 0) { send_message (-NO_XMIT_SOCKET, FATAL, "%s socket open failed %s", test_name, errmsg (errno)); } } bzero ((char *) &from, sizeof (from)); from.sin_family = AF_INET; from.sin_addr = valid_if[test_net].my_addr; from.sin_port = 0; if ((bind (psock, (char *) &from, sizeof (from))) < 0) { send_message (-NO_XMIT_SOCKET, FATAL, "%s socket bind failed %s", test_name, errmsg (errno)); } (void) ioctl (psock, FIONBIO, (char *) &dontblock); TRACE_OUT return (psock);}/****************************************************************************** in_cksum (fudged from ping.c) Checksum routine for Internet Protocol family headers (C Version)******************************************************************************/u_short in_cksum (addr, len)u_short *addr;int len;{ register int sum = 0; /* accumulator for checksum */ register int nleft = len; /* remaining bytes in buffer */ register u_short *w = addr; /* word pointer in buffer */ /* * 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. */ func_name = "in_chsum"; TRACE_IN while (nleft > 1) { sum += *w++; /* add 16 bits at a time */ nleft -= 2; } if (nleft == 1) sum += (int) (*(u_char *) w); /* * 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 */ TRACE_OUT return ((u_short) ~sum);}/****************************************************************************** net_dtablesize Return max # of possible file descriptors******************************************************************************/int net_dtablesize (){ static int called_already; if (!called_already) { called_already = getdtablesize (); } return (called_already);}/****************************************************************************** do_select This function calls the driver call 'select' with the 'what_select' status. It returns the residual 'time_count' to the calling routine. A return value of 0 should be interpreted as a timeout condition by the calling routine.******************************************************************************/int do_select (sock, what_select, time_count)int sock;int what_select;int time_count;{ fd_set sel_mask; int nfds = 0; /* total number of ready descriptors in all sets */ /* returned by calling select */ func_name = "do_select"; TRACE_IN for ( ; ((time_count > 0) && (nfds <= 0)); time_count--) { /* * get size of descriptor table size for this process and then * using it and then call select to get a mask of those descriptors * which are ready. The total number of ready descriptors is * returned in nfds. Select examines the I/O descriptors specified * by the bit masks readfds, writefds, and exceptfds to see if * they are ready for reading, writing, or have an exceptional * condition pending, respectively. Descriptor masks are reset * after each call to select since they are modified if no errors * occur. Resetting descriptor masks after each call to select * helps prevent bogus error reports when a timeout occurs. */ FD_ZERO (&sel_mask); /* initializing descriptor masks to null */ FD_SET (sock, &sel_mask); /* set/reset descriptor masks */ if (what_select == WRITE_SELECT) { nfds = select (net_dtablesize (), (fd_set *) NULL, &sel_mask, (fd_set *) NULL, &sel_time); } else { nfds = select (net_dtablesize (), &sel_mask, (fd_set *) NULL, (fd_set *) NULL, &sel_time); } if (nfds < 0) { send_message (-SELECT_ERROR, ERROR, "%s select %s", test_name, errmsg (errno)); } } TRACE_OUT return (time_count);}/****************************************************************************** ping_send This function sends out a ICMP packet out on the network. It sets up the packet with the appropriate information, generates the checksum, and then calls the function 'do_select' to check if the interface is ready for transmission. After this the packet is is shot out and the function returns. If it encounters any errors during this, the program is exited with an appropriate error code.******************************************************************************/void ping_send (sock, to, device)int sock;struct sockaddr_in *to;char *device;{ static u_char pack[MAXPACKLEN]; struct icmp *icmp_p = (struct icmp *) pack; struct timeval *time_p = (struct timeval *) & pack[8]; int len; func_name = "ping_send"; TRACE_IN (void) gettimeofday (¤t_time[seqno], (struct timezone *) NULL); bcopy ((char *) ¤t_time[seqno], (char *) time_p, sizeof (struct timeval)); icmp_p->icmp_type = ICMP_ECHO; icmp_p->icmp_code = 0; icmp_p->icmp_cksum = 0; icmp_p->icmp_seq = seqno++; icmp_p->icmp_id = id_pid; icmp_p->icmp_cksum = in_cksum ((u_short *) icmp_p, packetsize); if (do_select (sock, WRITE_SELECT, WAIT_TIME) == 0) { send_message (-TRANSMIT_BC_TIMEOUT, ERROR, "%s could not broadcast (timeout) on %s", test_name, device); } send_message (0, DEBUG, "%s: Broadcasting ICMP Packet (sendto), ICMP hdr info:", func_name); send_message (0, DEBUG, "Type=0x%x, Code=0x%x, Cksum=0x%x, Seq=0x%x, ID=0x%x, B-addr=%sData = 0x%x", icmp_p->icmp_type, icmp_p->icmp_code, icmp_p->icmp_cksum, icmp_p->icmp_seq, icmp_p->icmp_id, inet_ntoa (to->sin_addr), *time_p); /* is packet sent out = packetsize */ if ((len = sendto (sock, (char *) pack, packetsize, 0, (struct sockaddr *) to, sizeof (*to))) != packetsize) { send_message (0, DEBUG, "%s: send len=%d, packetsize=%d, System errno = %d", func_name, len, packetsize, errno); send_message (-NO_TRANSMIT_BC, ERROR, "%s Transmit failed on %s, broadcast packet %s", test_name, device, errmsg (errno)); } TRACE_OUT}/****************************************************************************** check_reply This function checks a packet for integrity. It checks all the information in the packet for correctness. Any error/mismatch results in the termination of checking the reply and displaying an appropriate message.******************************************************************************/int check_reply (buf, cc, from, device)char *buf; /* IP packet received */int cc; /* received packet length */struct sockaddr_in *from; /* INTERNET style socket address received */char *device;{ struct ip *ip; /* Struct of an INTERNET hdr, naked of options. */ struct icmp *icp; struct timeval *time_p; int hdr_len, c; int valid_reply = 1; u_short tmp, cksum_save; func_name = "check_reply"; TRACE_IN ip = (struct ip *) buf; /* convert to IP structure */ hdr_len = ip->ip_hl << 2; c = cc - hdr_len; icp = (struct icmp *) (buf + hdr_len); time_p = (struct timeval *) (buf + hdr_len + 8); /* * Start checking the packet now: * * packet type must be ICMP_ECHO. If the type is ICMP_UNREACH, then the * packet is not tagged as an error, instead it is ignored. * packet size * Verify checksum * Must be our packet (that is same process ID) * Must have the right sequence number * Must have the same time stamp for a valid sequence number */ if (icp->icmp_type != ICMP_ECHOREPLY) { if ((icp->icmp_type != ICMP_UNREACH) && (icp->icmp_type != ICMP_REDIRECT)) { if (print_warning) { send_message (0, WARNING, "%s type = %d, should be ICMP_ECHOREPLY, from %s, on %s", test_name, icp->icmp_type, inet_ntoa (from->sin_addr), device); } } TRACE_OUT return(!valid_reply); } if ((cc < hdr_len + ICMP_MINLEN) || (c != packetsize)) { if (print_warning) { send_message (0, WARNING, "%s bad pkt size %d should be %d, from %s, on %s", test_name, cc, packetsize, inet_ntoa (from->sin_addr), device); } TRACE_OUT return(!valid_reply); } cksum_save = icp->icmp_cksum; icp->icmp_cksum = 0; if ((tmp = in_cksum ((u_short *) icp, packetsize)) != cksum_save) { if (print_warning) { send_message (0, WARNING, "%s bad cksum:\tExpect 0x%hx\tGot: 0x%hx", test_name, icp->icmp_cksum, tmp); } TRACE_OUT return(!valid_reply); } icp->icmp_cksum = cksum_save; if (icp->icmp_id != id_pid) { if (print_warning) { send_message (0, WARNING, "%s pkt id (%d) not our pkt id (%d), from %s, on %s", test_name,icp->icmp_id,id_pid,inet_ntoa (from->sin_addr), device); } TRACE_OUT return(!valid_reply); } if (icp->icmp_seq >= seqno) { if (print_warning) { send_message (0, WARNING,"%s bad seq num:\tExp less than: %d\tGot: %d", test_name, seqno, icp->icmp_seq); } TRACE_OUT return(!valid_reply); } if (bcmp ((char *) ¤t_time[icp->icmp_seq], (char *) time_p, sizeof (struct timeval)) != 0) { if (print_warning) { send_message (0, WARNING, "%s packet data mis-compare (different time stamp), from %s, on %s", test_name, inet_ntoa (from->sin_addr), device); } TRACE_OUT return(!valid_reply); } TRACE_OUT return(valid_reply);}/****************************************************************************** test_reply This function tests a host that has replied to the broadcast net. It makes sure that the replying host has not previously failed. Then it does 3 tests. First it sprays large packets. Second it sprays small packets. Third, it tests UDP transmit. Once all three tests pass, this function is done and won't test further. Return status is true if tests have passed.******************************************************************************/int test_reply (from, test_net)struct sockaddr_in from; /* address of the responding node */int test_net;{ int test_succeeded = 0; struct hostent *replying_host; static char old_host_that_failed[256]; float packets_dropped = 0; /* percentage of packets dropped */ /* after spraying host: hp->h_name */ int sundiag_and_delay = 0; /* if sundiag flag (s) and spray */ /* delay option (D=) are specified */ /* * if sundiag_and_delay, use spray_cnt_large and spray_cnt_small instead * of the default spray_cnt value = 10000. spray_cnt_large and * spray_cnt_small are the number of packets required to make the * total stream size 100000 bytes */ int spray_cnt_large = 100000/1502; int spray_cnt_small = 100000/86; func_name = "test_reply";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -