649 lines
15 KiB
C
649 lines
15 KiB
C
//////////////////////////////////////////////////
|
|
//Title : pub_inet_test.c
|
|
//Auhtor : Liu Wei
|
|
//Desc : public ipnet function test
|
|
//Created : 2007-06-22
|
|
//Revision :
|
|
//
|
|
//Revision :
|
|
//
|
|
//////////////////////////////////////////////////
|
|
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/ip_icmp.h>
|
|
#include <sys/param.h>
|
|
#include <sys/ioctl.h>
|
|
#include <net/if.h>
|
|
#include <net/if_arp.h>
|
|
#include <netdb.h>
|
|
#include <setjmp.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
typedef unsigned char u8;
|
|
typedef unsigned int u32;
|
|
typedef unsigned short u16;
|
|
typedef unsigned long long u64;
|
|
|
|
|
|
#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;
|
|
}
|