网络安全实验报告(ping).doc

时间:2024.4.20

遵义师范学院计算机与信息科学学院

实  验  报  告

20122013学年第1学期

课程名称:     网络安全实验           

    级:  10级计1       

    号:      10410901049           

    名:        罗永龙              

任课教师:                    

《 网络安全扫描 》实验报告




第二篇:ping实验报告


一.实验目的

PING程序是我们使用的比较多的用于测试网络连通性的程序。PING程序基于ICMP,使用ICMP的回送请求和回送应答来工作。由计算机网络课程知道,ICMP是基于IP的一个协议,ICMP包通过IP的封装之后传递。

课程设计中选取PING程序的设计,其目的是希望同学们通过PING程序的设计,能初步掌握TCP/IP网络协议的基本实现方法,对网络的实现机制有进一步的认识。

二.实验内容和要求

1、RAW模式的SOCKET编程

PING程序是面向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。为了实现直接对IP和ICMP包进行操作,实验中使用RAW模式的SOCKET编程。

熟悉SOCKET的编程,包括基本的系统调用如SOCKET、BIND等;

2.具体内容

2.1定义数据结构

需要定义好IP数据报、ICMP包等相关的数据结构;

2.2程序实现

在WINDOWS环境下实现PING程序;

2.3程序要求

在命令提示符下输入:

      PING ΧΧΧ.ΧΧΧ.ΧΧΧ.ΧΧΧ

其中ΧΧΧ为目的主机的IP地址,不要求支持域名,对是否带有开关变量也不做要求。不带开关变量时,要求返回4次响应。

返回信息的格式:

      REPLY FROM ΧΧΧ.ΧΧΧ.ΧΧΧ.ΧΧΧ

      REQUEST TimeOut  (无法PING通的情况)。

三.基本思路及所涉及的相关理论

3.1 功能模块设计

本系统共有 4 个模块,分别是初始化模块、功能控制模块、数据控制模块、数据报解读模块和ping测试模块.

3.1.1 初始化模块。改模块用于初始化各个全局变量,为全局变量赋初始值;初始化,加载库。

3.1.2功能控制模块。改模块是被其它模块调用,其功能包括获取参数、计算校验和填充数据报文、释放占用资源和显示用户帮助。

3.1.3数据报解读模块。改模块用于解读接收到的报文和选项。

3.1.4测试模块。改模块是本程序的核心模块,调用其他模块实现其功能,主要是实现的功能。

3.2系统流程图

系统执行的流程图2.2所示。程序首先调用IniPing()函数初始化各全局变量,然后GetArgments()函数获取用户输入的参数,检查用户输入的参数,如果参数不正确或者没有输入参数,则显示用户帮助信息(User  help ),并结束程序;如果参数正确,则对指定目的地执行Ping命令,如果Ping通,则显示Ping结果并释放占用资源,如果没有Ping通,则报告错误信息,并释放占用资源。

图2.2 系统流程图

3.3参数获取(GetArgments()函数)流程

获取的参数包括“-r”(记录路由)、“-n”(记录条数程序,任意的整数)和datasize(数据报大小)。程序首先判断每一个参数的第一字符,如果第一个字符是“-”(短横线),则认为是“-r”或者“-n”中的一个,然后作进一步判断。如果该参数的第二个字符是数字,则判断该参数为记录的条数,如果该参数的第二个字符是“r”,则判断该参数为“-r”, 用于记录路由;如果参数的第一个字符是数字,则认为 参数是IP地址;或者datasize,然后作进一步的判断。如果该参数中不存在非数字的字符, 则判断该参数为datasize;如果存在非数 字的字符,则判断该参数为IP地址;其他情况则判断为主机名。

3.4ping()函数流程

ping()函数是本程序的核心部分它调用其他模块的函数来实现,其主要步骤包括创建接字,设置路由选项(如果需要的话)、设置接收和发送超时值、名字解析(如果需要的话)、分配内存、创建ICMP报文、发送ICMP请求报文、接收ICMP应答报文和解读ICMP报文。

四.数据结构设计

    本程序定义了3个结构体:-iphdr、-icmphdr、和-ipotionhdr,分别用于存放IP报头信息、ICM P报头信息和IP路由选项信息。

4.1定义IP报头结构体

Typedef struct _iphdr

{

     Unsigned       int       h_len:4;

Unsigned        int       version:4;

Unsigned        char      tos;

Unsigned        short     total_len;

Unsigned        short      ident;

Unsigned        short      frag_flags;

Unsigned        char      ttl;

Unsigned        chor      proto;

Unsigned        short      checksum;

Unsigned        int        sourceIP;

Unsigned        int        destIP;

} IpHeader;

其中各字段表示意义如下。

 h-len:4 :    表示IP报头长度,首部长度指的是首部占32bit字的数目,包括任何选项。由于它是一个4bit 字段,因此首部最长为60个字节,不包括任何选项的IP报头是20个字节。

 Version:4:   表示IP的版本号,这里表示Ipv4.。

                 Top:         表示服务的类型,最小时延,最大吞吐量,最高可靠性和最小费用。

 Total –len: 整个IP数据报的总长度。

 Ident:       唯一的标识符,标识主机发送的每一份数据报。

 Frag-flags:  分段标志,表示过长的数据报是否要分段。

 Ttl:         生存期,表示数据报可以经过的最多路由器数。

Proto:       协议类型(TCP、UDP等)。

Checksum:    校验和。

sourceIP:    源IP地址。

destIP:      目的IP地址。

4.2定义ICMP报头结构体

Typedef struct –icmphdr

  BYTE          i_type;

  BYTE          i_code :

  USHORT       i_cksum;

  USHORT        i_id;

  USHORT        i_seq;

  ULONG         timestamp;

}   IcmpHeader;

 其中各字段表示意义如下。

  I_tye :     ICMP 报文类型。

 I_code :    该类型中的代码号,一种ICMP 报文的类型号和该类型中的代码号共同决定。、

 I_cksum:     校验和。

 I_seq:       序列号,序列号从0开始,每发送一次新的回显请求就加1.

 Timestamp:   时间。

4.3定义IP 选项结构体

Typedef  struct  _ipoptionhdr

{

   Unsigned    char         code;

   Unsigned    char         len;

   Unsigned    char         ptr;

   Unsigned    loang        addr[9];

}     IcmpHeader;

其中各字段表示意义如下。

Code:       指明IP 选项类型,对于路由记录选项,它的值是7。

Len:        选项头长度。

  Ptr:       地址指针字段,是一个基于1的指针,指向存放下一个IP地址的位置。

addr[9]:     记录的Ip地址列表,由于IP首部中选项的空间有限,所以可以记录的Ip地址最多是9个.

五.各模块的代码

5.1初始化模块

void InitPing()

{

  WSADATA wsaData;

  icmp_data = NULL;

  seq_no = 0;

  recvbuf = NULL;

  RecordFlag = FALSE;

  lpdest = NULL;

  datasize = DEF_PACKET_SIZE;

  PacketNum = 5;

  SucessFlag = FALSE;

/*Winsock初始化*/

  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)

    {

        /*如果初始化不成功则报错,GetLastError()返回发生的错误信息*/

        printf("WSAStartup() failed: %d\n", GetLastError());

        return ;

    }

  m_socket = INVALID_SOCKET;

}

5.2功能控制模块

/*显示信息函数*/

void UserHelp()

{

    printf("UserHelp: ping -r <host> [data size]\n");

    printf("          -r           record route\n");

    printf("          -n           record amount\n");

    printf("          host         remote machine to ping\n");

    printf("          datasize     can be up to 1KB\n");

    ExitProcess(-1);

}

/*获取ping选项函数*/

void GetArgments(int argc,char** argv)

{

   int i;

   int j;

   int exp;

   int len;

   int m;

   /*如果没有指定目的地地址和任何选项*/

   if(argc == 1)

    {

        printf("\nPlease specify the destination IP address and the ping option as follow!\n");

        UserHelp();

    }

    for(i = 1; i < argc; i++)

    {

        len = strlen(argv[i]);

        if (argv[i][0] == '-')

        {

            /*选项指示要获取记录的条数*/

            if(isdigit(argv[i][1]))

           {

                PacketNum = 0;

                for(j=len-1,exp=0;j>=1;j--,exp++)

                    /*根据argv[i][j]中的ASCII值计算要获取的记录条数(十进制数)*/

                    PacketNum += ((double)(argv[i][j]-48))*pow(10,exp);

           }

           else

           {

                switch (tolower(argv[i][1]))

              {

                    /*选项指示要获取路由信息*/

                    case 'r':       

                        RecordFlag = TRUE;

                     break;

                    /*没有按要求提供选项*/

                  default:

                    UserHelp();

                     break;

              }

           }

        }

        /*参数是数据报大小或者IP地址*/

        else if (isdigit(argv[i][0]))

       {

            for(m=1;m<len;m++)

           {

                if(!(isdigit(argv[i][m])))

              {

                    /*是IP地址*/

                    lpdest = argv[i];

                  break;

               }

                /*是数据报大小*/

                else if(m==len-1)

                    datasize = atoi(argv[i]);          

           }

       }

        /*参数是主机名*/

        else

            lpdest = argv[i];

    }

}

/*求校验和函数*/

USHORT CheckSum(USHORT *buffer, int size)

{

    unsigned long cksum=0;

    while (size > 1)

    {

        cksum += *buffer++;

        size -= sizeof(USHORT);

    }

    if (size)

    {

        cksum += *(UCHAR*)buffer;

    }

    /*对每个16bit进行二进制反码求和*/

    cksum = (cksum >> 16) + (cksum & 0xffff);

    cksum += (cksum >>16);

    return (USHORT)(~cksum);

}

/*填充ICMP数据报字段函数*/

void FillICMPData(char *icmp_data, int datasize)

{

    IcmpHeader *icmp_hdr = NULL;

    char      *datapart = NULL;

    icmp_hdr = (IcmpHeader*)icmp_data;

    /*ICMP报文类型设置为回显请求*/

    icmp_hdr->i_type = ICMP_ECHO;       

    icmp_hdr->i_code = 0;

    /*获取当前进程IP作为标识符*/

    icmp_hdr->i_id = (USHORT)GetCurrentProcessId();

    icmp_hdr->i_cksum = 0;

    icmp_hdr->i_seq = 0;

    datapart = icmp_data + sizeof(IcmpHeader);

    /*以数字0填充剩余空间*/

    memset(datapart,'0',datasize-sizeof(IcmpHeader));

}

/*释放资源函数*/

void FreeRes()

{

    /*关闭创建的套接字*/

    if (m_socket != INVALID_SOCKET)

        closesocket(m_socket);

    /*释放分配的内存*/

    HeapFree(GetProcessHeap(), 0, recvbuf);

    HeapFree(GetProcessHeap(), 0, icmp_data);

    /*注销WSAStartup()调用*/

    WSACleanup();

    return ;

}

5.3数据报解读模块

/*解读IP选项头函数*/

void DecodeIPOptions(char *buf, int bytes)

{

    IpOptionHeader *ipopt = NULL;

    IN_ADDR inaddr;

    int i;

    HOSTENT *host = NULL;

    /*获取路由信息的地址入口*/

    ipopt = (IpOptionHeader *)(buf + 20);

    printf("RR:   ");

    for(i = 0; i < (ipopt->ptr / 4) - 1; i++)

    {

        inaddr.S_un.S_addr = ipopt->addr[i];

        if (i != 0)

            printf("      ");

        /*根据IP地址获取主机名*/

        host = gethostbyaddr((char *)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr), AF_INET);

        /*如果获取到了主机名,则输出主机名*/

        if (host)

            printf("(%-15s) %s\n", inet_ntoa(inaddr), host->h_name);

        /*否则输出IP地址*/

        else

            printf("(%-15s)\n", inet_ntoa(inaddr));

    }

    return;

}

/*解读ICMP报头函数*/

void DecodeICMPHeader(char *buf, int bytes, SOCKADDR_IN *from)

{

    IpHeader *iphdr = NULL;

    IcmpHeader *icmphdr = NULL;

    unsigned short iphdrlen;

    DWORD tick;

    static int icmpcount = 0;

    iphdr = (IpHeader *)buf;

    /*计算IP报头的长度*/

    iphdrlen = iphdr->h_len * 4;

    tick = GetTickCount();

   

    /*如果IP报头的长度为最大长度(基本长度是20字节),则认为有IP选项,需要解读IP选项*/

    if ((iphdrlen == MAX_IP_HDR_SIZE) && (!icmpcount))

        /*解读IP选项,即路由信息*/

        DecodeIPOptions(buf, bytes);

    /*如果读取的数据太小*/

    if (bytes < iphdrlen + ICMP_MIN)

    {

        printf("Too few bytes from %s\n",

            inet_ntoa(from->sin_addr));

    }

    icmphdr = (IcmpHeader*)(buf + iphdrlen);

    /*如果收到的不是回显应答报文则报错*/

    if (icmphdr->i_type != ICMP_ECHOREPLY)

    {

        printf("nonecho type %d recvd\n", icmphdr->i_type);

        return;

    }

    /*核实收到的ID号和发送的是否一致*/

    if (icmphdr->i_id != (USHORT)GetCurrentProcessId())

    {

        printf("someone else's packet!\n");

        return ;

    }

    SucessFlag = TRUE;

    /*输出记录信息*/

    printf("%d bytes from %s:", bytes, inet_ntoa(from->sin_addr));

    printf(" icmp_seq = %d. ", icmphdr->i_seq);

    printf(" time: %d ms", tick - icmphdr->timestamp);

    printf("\n");

   icmpcount++;

    return;

}

4Ping 测试模块

/*ping函数*/

void PingTest(int timeout)

{  

    int ret;

    int readNum;

    int fromlen;

    struct hostent *hp = NULL;

    /*创建原始套接字,该套接字用于ICMP协议*/

    m_socket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,WSA_FLAG_OVERLAPPED);

    /*如果套接字创建不成功*/

    if (m_socket == INVALID_SOCKET)

    {

        printf("WSASocket() failed: %d\n", WSAGetLastError());

        return ;

    }

/*若要求记录路由选项*/

    if (RecordFlag)

    {

        /*IP选项每个字段用0初始化*/

        ZeroMemory(&IpOption, sizeof(IpOption));

        /*为每个ICMP包设置路由选项*/

        IpOption.code = IP_RECORD_ROUTE;

        IpOption.ptr  = 4;              

        IpOption.len  = 39;             

       ret = setsockopt(m_socket, IPPROTO_IP, IP_OPTIONS,(char *)&IpOption, sizeof(IpOption));

        if (ret == SOCKET_ERROR)

        {

            printf("setsockopt(IP_OPTIONS) failed: %d\n",WSAGetLastError());

        }

    }

/*设置接收的超时值*/

    readNum = setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout, sizeof(timeout));

    if(readNum == SOCKET_ERROR)

    {

        printf("setsockopt(SO_RCVTIMEO) failed: %d\n",WSAGetLastError());

        return ;

    }

    /*设置发送的超时值*/

    timeout = 1000;

    readNum = setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO,(char*)&timeout, sizeof(timeout));

    if (readNum == SOCKET_ERROR)

    {

        printf("setsockopt(SO_SNDTIMEO) failed: %d\n",WSAGetLastError());

        return ;

    }

/*用0初始化目的地地址*/

    memset(&DestAddr, 0, sizeof(DestAddr));

    /*设置地址族,这里表示使用IP地址族*/

    DestAddr.sin_family = AF_INET;

    if ((DestAddr.sin_addr.s_addr = inet_addr(lpdest)) == INADDR_NONE)

    {  

           

        /*名字解析,根据主机名获取IP地址*/

        if ((hp = gethostbyname(lpdest)) != NULL)

        {

            /*将获取到的IP值赋给目的地地址中的相应字段*/

            memcpy(&(DestAddr.sin_addr), hp->h_addr, hp->h_length);

            /*将获取到的地址族值赋给目的地地址中的相应字段*/

            DestAddr.sin_family = hp->h_addrtype;

            printf("DestAddr.sin_addr = %s\n", inet_ntoa(DestAddr.sin_addr));

        }

        /*获取不成功*/

        else

        {

            printf("gethostbyname() failed: %d\n",WSAGetLastError());

            return ;

        }

}       

/*数据报文大小需要包含ICMP报头*/

    datasize += sizeof(IcmpHeader); 

    /*根据默认堆句柄,从堆中分配MAX_PACKET内存块,新分配内存的内容将被初始化为0*/

    icmp_data =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET);

    recvbuf =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET);

/*如果分配内存不成功*/

    if (!icmp_data)

    {

        printf("HeapAlloc() failed: %d\n", GetLastError());

        return ;

    }

    /* 创建ICMP报文*/

    memset(icmp_data,0,MAX_PACKET);

FillICMPData(icmp_data,datasize);

while(1)

    {

        static int nCount = 0;

        int writeNum;

        /*超过指定的记录条数则退出*/       

        if (nCount++ == PacketNum)

            break;

/*计算校验和前要把校验和字段设置为0*/      

        ((IcmpHeader*)icmp_data)->i_cksum = 0;

        /*获取操作系统启动到现在所经过的毫秒数,设置时间戳*/

        ((IcmpHeader*)icmp_data)->timestamp = GetTickCount();

        /*设置序列号*/

        ((IcmpHeader*)icmp_data)->i_seq = seq_no++;

        /*计算校验和*/

        ((IcmpHeader*)icmp_data)->i_cksum = CheckSum((USHORT*)icmp_data, datasize);

        /*开始发送ICMP请求 */

        writeNum = sendto(m_socket, icmp_data, datasize, 0,(struct sockaddr*)&DestAddr, sizeof(DestAddr));

       /*如果发送不成功*/

        if (writeNum == SOCKET_ERROR)

        {

            /*如果是由于超时不成功*/

            if (WSAGetLastError() == WSAETIMEDOUT)

            {

                printf("timed out\n");

                continue;

            }

            /*其他发送不成功原因*/

            printf("sendto() failed: %d\n", WSAGetLastError());

            return ;

        }

/*开始接收ICMP应答 */

        fromlen = sizeof(SourceAddr);

        readNum = recvfrom(m_socket, recvbuf, MAX_PACKET, 0,(struct sockaddr*)&SourceAddr, &fromlen);

        /*如果接收不成功*/

        if (readNum == SOCKET_ERROR)

        {

            /*如果是由于超时不成功*/

            if (WSAGetLastError() == WSAETIMEDOUT)

            {

                printf("timed out\n");

                continue;

            }

            /*其他接收不成功原因*/

            printf("recvfrom() failed: %d\n", WSAGetLastError());

            return ;

        }

        /*解读接收到的ICMP数据报*/

        DecodeICMPHeader(recvbuf, readNum, &SourceAddr);

    }

}

5.5主函数

int main(int argc, char* argv[])

{  

    InitPing(); 

    GetArgments(argc, argv);

    PingTest(1000);

    /*延迟1秒*/

    Sleep(1000);

    if(SucessFlag)

        printf("\nPing end, you have got %.0f records!\n",PacketNum);

    else

        printf("Ping end, no record!");  

    FreeRes();

    getchar();

    return 0;

 }

六.心得和总结

此次做的是win32控制台程序,按照书上和网上找的资料和教程,编译无误

没有太大的问题,最后执行程序的时候要通过系统的cmd命令来运行,结果如下图:

七.运行和调试:

6.参考文献:

《《Visual c++高级编程》》,张力 ,人民邮电出版社,20##年3月。

《《Visual c++实践与提高 网络编程篇》》,汪翔,袁辉,中国铁道出版社,20##年3月。

更多相关推荐:
网络安全 实验报告

首都经济贸易大学信息学院实验报告实验课程名称网络安全技术首都经济贸易大学信息学院计算机系制实验报告学号实验地点3机房姓名实验时间一实验室名称网络安全实验二实验项目名称冰河木马攻击三实验原理原理特洛伊木马简称木马...

网络安全实验二报告

实验报告20xx20xx学年第1学期课程名称网络安全实验班级10级lt一gt班学号10410901036姓名陈志军任课教师蒲晓川计算机与信息科学学院实验报告0遵义师范学院计算机与信息科学学院目录错误未指定书签M...

网络安全实验报告

网络安全实验学生张守军实验目的1一我要搭建网络安全实验环境配置良好的实验环境时进行网络安全实验的基础工作1VMware虚拟机的安装和配置首先在一台计算机上安装一套操作系统然后安装虚拟软件VMware分别在虚拟机...

网络与信息安全实验报告

中国海洋大学课程名称:网络与信息安全任课教师:学生姓名:学生学号:专业班级:计算机信息保密2010级学院名称:信息科学与工程学院20XX年12月20日实验一(报文监听)一、实验目的1.安装、配置、使用、卸载报文…

网络安全实验报告 模板啊

虚拟机的安装一实验目的1了解虚拟机在构建网络安全实验平台的作用2熟悉虚拟机实验环境的搭建3在VmwareWorkstation虚拟机软件上安装使用操作系统二实验仪器与器材装有WindowsXP系统的PC机三实验...

信息安全实验报告3-1

课程实验报告12

网络安全应用实训报告

安全技术及应用实训项目二网络安全应用实训项目报告学号09011319姓名雷超信息技术分院长春职业技术学院目录任务1知识剖析111信息的加密传输1任务2数字签名2任务3数据安全传输4任务4创建根CA服务器5任务5...

网络安全实验报告

科技学院课程设计综合实验报告20xx20xx年度第1学期名称网络信息安全综合实验题院系信息工程系班级网络12K1学号1219xx030128学生姓名张国楠指导教师李莉朵春红设计周数成绩日期20xx1224网络信...

信息安全基础实验报告——凯撒密码(java)

信息安全基础实验报告凯撒密码java一设计流程图二源代码importjavautilpublicclassTestpublicstaticvoidmainStringargschars1newchar1000i...

网络安全实验报告书

网络安全实验报告姓名班级白晨软件22指导老师田暄提交日期20xx1210目录1加解密与认证21112132实验环境2源代码与注释2运行结果与分析2RC4流密码加密实现10212223实验环境10源代码与注释10...

网络安全实验报告 (5)

网络安全实验报告实验序号5实验项目名称木马攻击与防范实验

计算机网络安全与工程专题实验报告-C

计算机网络安全与工程专题实验报告学院班级学号姓名20xx年12月26日报告撰写注意事项1每位同学独立写一份尽量体现个人实验现场及特点避免同组二人完全拷贝2报告提交截至时间实验完成后一周内文件名学号姓名地址VLA...

网络安全实验报告(24篇)