////////////////////////////////////////////////// //Title : pub_inet_test.c //Auhtor : Liu Wei //Desc : public ipnet function test //Created : 2007-06-22 //Revision : // //Revision : // ////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef unsigned char u8; typedef unsigned int u32; typedef unsigned short u16; #define MAXINTERFACES 16 typedef struct EIF { u32 dIfIP; u8 uIfState; } EIF; typedef struct IF_ADDR { EIF tIfEntity[MAXINTERFACES]; u8 uIfNum; } IfAddr; int GetNetIfInfo ( IfAddr * pIfAddr ) { int fd; struct ifreq buf[MAXINTERFACES]; struct arpreq arp; struct ifconf ifc; pIfAddr->uIfNum = 0; if( ( fd = socket ( AF_INET, SOCK_DGRAM, 0 ) ) >= 0 ) { ifc.ifc_len = sizeof buf; ifc.ifc_buf = ( caddr_t ) buf; if( !ioctl ( fd, SIOCGIFCONF, ( char * ) &ifc ) ) { int i; pIfAddr->uIfNum = ifc.ifc_len / sizeof ( struct ifreq ); pIfAddr->uIfNum = pIfAddr->uIfNum % MAXINTERFACES; for ( i = 0; i < pIfAddr->uIfNum; i++ ) { ioctl ( fd, SIOCGIFFLAGS, ( char * ) &buf[i] ); pIfAddr->tIfEntity[i].uIfState = buf[i].ifr_flags & IFF_UP; if( !( ioctl ( fd, SIOCGIFADDR, ( char * ) &buf[i] ) ) ) { pIfAddr->tIfEntity[i].dIfIP = ( ( struct sockaddr_in * ) ( &buf[i].ifr_addr ) )->sin_addr.s_addr; } } } } close ( fd ); return pIfAddr->uIfNum; } #define PACKET_SIZE 4096 #define MAX_NO_PACKETS 3 struct sockaddr_in dest_addr; struct sockaddr_in from; struct timeval tvrecv; typedef void PingCallBack( int nPingResult ); typedef struct ICMP_SERVICE { u8 uSrvState; u8 uPingResult; u8 uIcmpState; u8 uPackNo; u8 uDataLen; u8 nPackNumSend; u8 nPackNumRecv; u8 aSendBuff[PACKET_SIZE]; u8 aRecvBuff[PACKET_SIZE]; u32 wSockfd; pid_t tPid; struct protoent *pProtoent; PingCallBack *fCallBack; } IcmpSrv; IcmpSrv tIcmpSrvEntity; //校验和算法 u16 IcmpCheckSum ( u16 *addr, int len ) { int nleft = len; int sum = 0; u16 *w = addr; u16 answer = 0; //把ICMP报头二进制数据以2字节为单位累加起来 while ( nleft > 1 ) { sum += *w++; nleft -= 2; } //若ICMP报头为奇数个字节,会剩下最后一字节。 //把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加 if( nleft == 1 ) { *( unsigned char * ) ( &answer ) = *( unsigned char * ) w; sum += answer; } sum = ( sum >> 16 ) + ( sum & 0xffff ); sum += ( sum >> 16 ); answer = ~sum; return answer; } //设置ICMP报头 int IcmpPacking ( IcmpSrv *pIS ) { int i, packsize; struct icmp *icmp; struct timeval *tval; icmp = ( struct icmp * ) pIS->aSendBuff; icmp->icmp_type = ICMP_ECHO; icmp->icmp_code = 0; icmp->icmp_cksum = 0; icmp->icmp_seq = pIS->nPackNumSend; icmp->icmp_id = pIS->tPid; packsize = 8 + pIS->uDataLen; //记录发送时间 tval = ( struct timeval * ) icmp->icmp_data; gettimeofday ( tval, NULL ); icmp->icmp_cksum = IcmpCheckSum ( (u16 *)icmp, packsize ); return packsize; } //剥去ICMP报头 int IcmpUnPack ( u8 *buf, int len , IcmpSrv *pIS ) { int i, nIpHdrLen; struct ip *pIP; struct icmp *icmp; struct timeval *tvSend; struct timeval tvRecv; double rtt; gettimeofday ( &tvRecv, NULL ); pIP = ( struct ip * ) buf; //求ip报头长度,即ip报头的长度标志乘4 nIpHdrLen = pIP->ip_hl << 2; //越过ip报头,指向ICMP报头 icmp = ( struct icmp * ) ( buf + nIpHdrLen ); //ICMP报头及ICMP数据报的总长度 len -= nIpHdrLen; if( len < 8 ) //小于ICMP报头长度则不合理 { printf ( "ICMP packets's length is less than 8 " ); return 0; } //确保所接收的是我所发的的ICMP的回应 if( ( icmp->icmp_type == ICMP_ECHOREPLY ) && ( icmp->icmp_id == pIS->tPid ) ) { tvSend = ( struct timeval * ) icmp->icmp_data; rtt = ( tvRecv.tv_sec * 1000 + tvRecv.tv_usec / 1000 ) - ( tvSend->tv_sec * 1000 + tvSend->tv_usec / 1000 ); printf ( "%d byte from %s: icmp_seq=%u ttl=%d rtt=%.3f ms \n" , len, inet_ntoa ( from.sin_addr ) , icmp->icmp_seq, pIP->ip_ttl, rtt ); return 1; } return 0; } void IcmpStatis ( IcmpSrv *pIS ) { int nSend , nRecv ; nSend = pIS->nPackNumSend; nRecv = pIS->nPackNumRecv; printf ( " --------------------PING statistics------------------- \n" ); printf ( "%d packets transmitted, %d received , %%%d lost \n\n" , nSend, nRecv, ( nSend - nRecv ) / nSend * 100 ); close ( pIS->wSockfd ); pIS->uSrvState = 0; } //发送三个ICMP报文 int IcmpSend ( IcmpSrv *pIS ) { int nSize; if ( pIS->nPackNumSend < MAX_NO_PACKETS ) { pIS->nPackNumSend++; nSize = IcmpPacking ( pIS ); //设置ICMP报头 if( sendto ( pIS->wSockfd, pIS->aSendBuff, nSize, 0, ( struct sockaddr * ) &dest_addr, sizeof ( dest_addr ) ) < 0 ) { perror ( "sendto error" ); return 0; } printf("[IcmpSend] : Send icmp Pack %d \n" , pIS->nPackNumSend); return 1; } return 0; } //接收所有ICMP报文 void IcmpRecv ( IcmpSrv *pIS ) { int n, fromlen; extern int errno; fromlen = sizeof ( from ); while ( pIS->nPackNumRecv < pIS->nPackNumSend ) { if( ( n = recvfrom ( pIS->wSockfd, pIS->aRecvBuff, sizeof ( pIS->aRecvBuff ), 0, ( struct sockaddr * ) &from, &fromlen ) ) < 0 ) { if( errno == EINTR ) continue; perror ( "recvfrom error" ); continue; } if( IcmpUnPack ( pIS->aRecvBuff, n , pIS ) == -1 ) continue; pIS->nPackNumRecv++; } } int PingInit ( IcmpSrv *pIS , int nDataLen ) { memset( pIS , 0 , sizeof(IcmpSrv) ); pIS->uSrvState = 0; pIS->uDataLen = 56; if( ( pIS->pProtoent = getprotobyname ( "icmp" ) ) == NULL ) { perror ( "getprotobyname" ); exit ( 1 ); } // 回收root权限,设置当前用户权限 setuid ( getuid ( ) ); //获取main的进程id,用于设置ICMP的标志符 pIS->tPid = getpid ( ); } int PingTimer ( IcmpSrv *pIS ) { if( pIS->uSrvState ) { IcmpRecv( pIS ); switch( pIS->uIcmpState ) { case 1: case 2: case 3: IcmpSend( pIS ); pIS->uIcmpState++; break; default: if( pIS->nPackNumRecv >= 3 ) { IcmpStatis( pIS ); pIS->fCallBack( 1 ); } if( pIS->uIcmpState++ > 200 ) { IcmpStatis( pIS ); pIS->fCallBack( 0 ); } break; } } } int PingStart( IcmpSrv *pIS , char *sIP , PingCallBack fCallBack ) { int nSize; struct hostent *pHost; //struct in_addr *pInAddr; u32 nInetAddr; if( pIS->uSrvState ) { return 0; } pIS->fCallBack = fCallBack; //生成使用ICMP的原始套接字,这种套接字只有root才能生成 if( ( pIS->wSockfd = socket ( AF_INET, SOCK_RAW, pIS->pProtoent->p_proto ) ) < 0 ) { perror ( "socket error" ); exit ( 1 ); } //扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的 //的可能性, 若无意中ping会引来大量应答 setsockopt ( pIS->wSockfd, SOL_SOCKET, SO_RCVBUF, &nSize, sizeof ( nSize ) ); bzero ( &dest_addr, sizeof ( dest_addr ) ); dest_addr.sin_family = AF_INET; //判断是主机名还是ip地址 nInetAddr = inet_addr ( sIP ) ; if( nInetAddr == INADDR_NONE ) { if( ( pHost = gethostbyname ( sIP ) ) == NULL ) //是主机名 { perror ( "gethostbyname error" ); exit ( 1 ); } memcpy ( ( char * ) &dest_addr.sin_addr, pHost->h_addr, pHost->h_length ); } else //是ip地址 { dest_addr.sin_addr.s_addr = nInetAddr; //memcpy( (char *)&dest_addr,(char *)&nInetAddr,host->h_length); } printf ( "PING %s(%s): %d bytes data in ICMP packets. \n", sIP , inet_ntoa ( dest_addr.sin_addr ) , pIS->uDataLen ); pIS->uSrvState = 1 ; pIS->uIcmpState = 1; } //打印ip报文的信息 void printIP ( char *packet, int len ) { struct sockaddr_in addr_src, addr_dst; struct ip *pip = ( struct ip * ) packet; printf ( "ip head len:%d ", pip->ip_hl << 2 ); printf ( "ip len:%d ", ntohs ( pip->ip_len ) ); printf ( "ip pro id:%d ", pip->ip_p ); printf ( "ip ttl:%d ", pip->ip_ttl ); printf ( "ip offset:%d ", ntohs ( pip->ip_off ) & IP_OFFMASK ); memset ( &addr_src, 0, sizeof ( struct sockaddr_in ) ); memset ( &addr_dst, 0, sizeof ( struct sockaddr_in ) ); memcpy ( &addr_src, &pip->ip_src, sizeof ( struct sockaddr_in ) ); memcpy ( &addr_dst, &pip->ip_dst, sizeof ( struct sockaddr_in ) ); printf ( "src ip:%x ", addr_src.sin_addr ); printf ( "dst ip:%x ", addr_dst.sin_addr ); } void NetCapPing( int nRet ) { if( nRet ) { printf("Host is rearchable\n"); } else { printf("Host is not rearchable\n"); } } static char *pStrEqTok = NULL; static u8 uStrEqState = 0; #define CNULL '\0' #define STR_CHECK_END(str,ch) ( str[strlen(str)-1] == ch ) #define STR_CUT_LAST(str) ( str[strlen(str)-1] = CNULL ) void StrTrimMoreSpace(char *pStr ) { char *pSrc , *pDst , *pCh; pDst = pStr; pCh = pSrc = strdup( pStr ); for( ; *pSrc ; pSrc++ ) { if( !( isspace(*pSrc) && isspace( *(pSrc+1) ) ) ) { *pDst++ = *pSrc; } } *pDst = CNULL; } char *StrEqTok( char *pStr ) { char *p, *pCh; char *pDel = " "; pCh = NULL; if( pStr == NULL ) { pStr = pStrEqTok; } else { pStr += strspn (pStr, pDel); if (*pStr == '\0') { pStrEqTok = NULL; return NULL; } StrTrimMoreSpace( pStr ); } if( pStr == NULL ) { return NULL; } uStrEqState = uStrEqState > 2 ? 0 : uStrEqState; pCh = strpbrk (pStr, pDel ); if( pCh == NULL ) { pStrEqTok = NULL; pCh = pStr; } else { pStrEqTok = pCh + 1; *pCh = CNULL; pCh = pStr; } p = strchr( pCh , '='); if( p == NULL ) { if( pStrEqTok == NULL ) { goto STREQTOK_CLEAN_UP; } if( uStrEqState == 0 || uStrEqState == 2 ) { //expres left and right uStrEqState++; return pCh; } else { //Miss '=' goto STREQTOK_CLEAN_UP; } } else { if( uStrEqState == 0 && STR_CHECK_END( pCh , '=') ) { //expres left and '=' uStrEqState+=2; STR_CUT_LAST(pCh); return pCh; } else if( uStrEqState == 1 && pCh[0] == '=') { //'=' meet if( pCh[1] == CNULL ) { if( pStrEqTok == NULL ) { goto STREQTOK_CLEAN_UP; } pStr = pStrEqTok; pCh = strpbrk (pStr, pDel); if( pCh == NULL ) { pStrEqTok = NULL; pCh = pStr; } else { pStrEqTok = pCh + 1; *pCh = CNULL; pCh = pStr; } uStrEqState = 3; return pCh; } else { //expres '=' and right uStrEqState = 3; //all meet return ++pCh; } } else if( uStrEqState == 0 ) { //expres left and '=' and right if( pStrEqTok != NULL ) { *(pStrEqTok -1) = ' '; } pStrEqTok = p + 1; *p = CNULL; uStrEqState = 2; return pCh; } else { goto STREQTOK_CLEAN_UP; } } STREQTOK_CLEAN_UP: pStrEqTok = NULL; uStrEqState = 0; return NULL; } int main ( ) { int i, ret = 0; IfAddr tIfAddr; IcmpSrv tIcmpSrv; char tmpStr[80]; ret = GetNetIfInfo ( &tIfAddr ); printf ( "Interface num :%d \n\n", ret ); for ( i = 0; i < ret; i++ ) { printf ( "If %d : state : %d ip : %s \n\n" , i, tIfAddr.tIfEntity[i].uIfState , inet_ntoa ( *((struct in_addr* )&tIfAddr.tIfEntity[i].dIfIP )) ); } #define STR(s) #s printf(STR(if(NOTSO(a)) return 0\n)); #define FPOS( type, field ) /*lint -e545 */ ( (u32) &(( type *) 0)-> field ) /*lint +e545 */ #define FSIZ( type, field ) sizeof( ((type *) 0)->field ) printf("Pos : %ld \n" , FPOS(IfAddr ,uIfNum ) ); printf("Size : %ld \n" , FSIZ(IfAddr ,uIfNum ) ); printf("Pos : %ld \n" , FPOS(IfAddr ,tIfEntity ) ); printf("Size : %ld \n" , FSIZ(IfAddr ,tIfEntity ) ); printf("Pos : %ld \n" , FPOS(EIF ,dIfIP ) ); printf("Size : %ld \n" , FSIZ(EIF ,dIfIP ) ); printf("Pos : %ld \n" , FPOS(EIF ,uIfState ) ); printf("Size : %ld \n" , FSIZ(EIF ,uIfState ) ); printf("Pos : %ld \n" , FPOS(IcmpSrv ,nPackNumSend ) ); printf("Size : %ld \n" , FSIZ(IcmpSrv ,nPackNumSend ) ); printf("Pos : %ld \n" , FPOS(IcmpSrv ,aSendBuff ) ); printf("Size : %ld \n" , FSIZ(IcmpSrv ,aSendBuff ) ); printf("Please input ip and port : "); fgets( tmpStr, 80 ,stdin ); printf("%s\n", tmpStr); if( STR_CHECK_END(tmpStr , '\n' ) ) { STR_CUT_LAST(tmpStr ); } //StrTrimMoreSpace(tmpStr); //printf("trim space : \n%s\n" ,tmpStr ); { char *p = NULL; u8 uFlag = 0; p = StrEqTok(tmpStr); printf( "Name: %-20s " , p); for( ; p = StrEqTok(NULL); ) { uFlag = uFlag ? 0 : 1; if( uFlag ) { printf( "Valu: %-20s \n" , p); } else { printf( "Name: %-20s " , p); } } } printf("\n\n"); PingInit( &tIcmpSrv , 56 ); ret = PingStart( &tIcmpSrv , "172.18.99.1" , NetCapPing ); if( !ret ) { printf("ping is processing\n"); } while(1) { PingTimer( &tIcmpSrv ); sleep ( 1 ); //每隔一秒发送一个ICMP报文 } return 1; }