网络协议分析习题解答参考思路.docx
《网络协议分析习题解答参考思路.docx》由会员分享,可在线阅读,更多相关《网络协议分析习题解答参考思路.docx(49页珍藏版)》请在冰豆网上搜索。
网络协议分析习题解答参考思路
《网络协议分析与实现》习题解答参考思路
第1章习题解答参考思路
习题1:
该题考查对异构网络互联概念、异构网络涉及的问题以及解决方法的理解程度。
其中涉及的问题包括地址问题、包格式转换问题、路由问题等,其中1.1.3节还列举了很多其他的问题。
习题2:
该题可参考教材中所讲述的用户A和用户B的数据转换和传输过程进行解答。
习题3:
该题主要考查网上查找资料的能力。
在http:
//www.rfc-editor.org/网站上可以查到所有的RFC信息。
习题4:
TCP/IP模型和OSI参考模型之间的层次对应关系及各层协议参见教材中的图1-5。
习题5:
该题主要考查动手能力,可以使用Wireshark(曾称为Ethereal)、SnifferPortable等软件进行抓包,然后针对一些具体报文进行分析。
注意分析通信中的多路复用和多路分解过程,说出通信双方的物理地址、IP地址和端口地址。
习题6:
该题主要考查阅读代码的能力,这部分代码是对数据结构课程中队列操作的一个实现。
该队列是一个基于优先级排序的队列,主要的数据结构是qinfo:
structqinfo{
Boolq_valid;
intq_type;/*mutextype*/
intq_max;
intq_count;
intq_seen;
intq_mutex;
int*q_key;
char**q_elt;
};
具体操作如下:
intenq(intq,void*elt,intkey);
/*入队列操作,根据key的大小插到队列中的合适位置*/
void*deq(intq);/*出队列操作*/
void*headq(intq);/*获取队列头部元素*/
void*seeq(intq);/*按顺序取队列元素*/
intnewq(unsignedsize,unsignedmtype);
/*分配一个新的队列,并返回队列的索引位置*/
intfreeq(intq);/*释放队列*/
intlenq(intq);/*获取队列长度*/
staticintinitq();/*初始化队列*/
第2章习题解答参考思路
习题1:
该题主要考查对HDLC概念的理解程度,答案参见2.1节。
习题2:
该题主要考查对SLIP、PPP之间的关系,PPP对SLIP的改进以及PPPoE的概念的理解程度。
SLIP和PPP可以在教材中找到参考资料,PPPoE可以到网上或RFC中查找参考资料。
PPPoE全称为PointtoPointProtocoloverEthernet(以太网上的点对点协议),简单地说,就是以太网和PPP结合后的协议,目前广泛应用在ADSL接入方式中。
通过PPPoE技术和宽带调制解调器(比如ADSLModem)可以实现高速宽带网的个人身份验证访问,为每个用户创建虚拟拨号连接,这样就可以高速连接入因特网。
(1)PPP在SLIP的基础上的改进之处
●提供了校验机制,可以对每一帧进行检查;
●提供了IP地址的动态协商机制,使通信双方能够得知对方的IP地址;
●在一条串行链路上提供了对多协议的支持;
●提供了对TCP和IP数据报首部的压缩机制。
(2)PPPoE和PPP的关系
PPP提供了一种标准的方式在点对点的链路上传输多种网络层协议的数据报。
它要求通信双方之间是点到点的关系,由于不适用于广播类型的以太网和另外一些多点访问类型的网络,因此就产生了PPPoE。
在实际应用中,PPPoE利用以太网的工作机理,将ADSLModem的10BASE-T接口与内部以太网互联,在ADSLModem中采用RFC1483的桥接封装方式对终端发出的PPP报文进行LLC/SNAP封装后,通过连结两端的PVC在ADSLModem与网络侧的宽带接入服务器之间建立连接,实现PPP的动态接入。
PPPoE接入利用在网络侧和ADSLModem之间的一条PVC(永久虚拟电路)就可以完成以太网上多用户的共同接入,实际组网方式简单,实用方便,大大降低了网络的复杂程度。
PPPoE的实质就是以太网和拨号网络之间的一个中继协议,它继承了以太网的快速和PPP拨号的简单、用户验证、IP分配等优点。
(3)PPPoE的工作流程
PPPoE提供了在广播式网络(如以太网)中多台主机连接到远端的访问集中器上的一种标准。
在这种网络模型中,不难看出所有用户的主机都需要能独立地初始化自己的PPP协议栈,而且通过PPP本身所具有的一些特点能在广播式网络上对用户进行计费和管理。
为了能在广播式网络上建立、维持各主机与访问集中器之间点对点的关系,需要每个主机与访问集中器之间建立唯一的点到点的会话。
PPPoE共包括两个阶段,即PPPoE的发现阶段(PPPoEDiscoveryStage)和PPPoE的会话阶段(PPPoESessionStage)。
①发现阶段:
此阶段用来建立连接,如下图所示,当一个用户主机想开始一个PPPoE会话时,首先必须经过发现阶段以识别PPPoEServer的以太网MAC地址,并建立一个PPPoE会话标识(SessionID)。
如上图所示,该阶段的基本工作流程由4个步骤组成。
PADI:
如果要建立一条PPPoE连接,首先PPPoE客户端要以广播的方式发送一个PADI(PPPoEActiveDiscoveryInitiation)报文,PADI报文包括客户端请求的服务。
PADO:
在PPPoE服务器(BRAS)收到一个PADI报文之后,它会判断自己是否能够提供服务,如果能够提供服务,就会向客户端发送PADO(PPPoEActiveDiscoveryOffer)报文来进行回应。
PADO报文包括PPPoE服务器名称和与PADI报文中相同的服务名;如果PPPoE服务器不能为PADI提供服务,则不允许用PADO报文应答。
PADR:
由于PADI是以广播的形式发送出去的,PPPoE客户端可能会收到不止一个PADO报文,它将审查所有接收到的PADO报文并根据其中的服务器名或所提供的服务选择一个PPPoE服务器,同时向选中的服务器发送PADR(PPPoEActiveDiscoveryRequest)报文。
PADR报文包括客户端所请求的服务。
PADS:
当PPPoE服务器收到客户端发送的PADR报文时,它准备开始一个PPPoE会话。
它为PPPoE会话创建一个唯一的PPPoE会话标识,并向客户端发送PADS(PPPoEActiveDiscoverySession-confirmation)报文作为应答。
当发现阶段正常结束后,通信的两端都会获得会话标识和对方的MAC地址,它们一起唯一定义一个PPPoE会话。
②会话阶段:
PPPoE进入PPP会话阶段后,客户端和服务器将进行标准的PPP协商,PPP协商通过后,数据通过PPP封装发送。
PPP报文作为PPPoE帧的净荷被封装在以太网帧内,发送到PPPoE链路的对端。
会话标识必须是发现阶段确定的标识,并且在会话过程中保持不变,MAC地址必须是对端的MAC地址。
在会话阶段的任意时刻,PPPoE服务器和客户端都可向对方发送PADT(PPPoEActiveDiscoveryTerminate)报文通知对方结束本会话。
收到PADT以后,就不再允许使用该会话发送PPP流量了。
在发送或接收到PADT报文后,即使是常规的PPP结束报文也不允许发送。
一般情况下,PPP通信双方使用PPP报文自身来结束PPPoE会话,但在无法使用PPP时可以使用PADT来结束会话。
(4)帧结构及其应用
版本4位
类型4位
代码8位
会话标识16位
长度16位
净载荷
发现阶段承载一些标记
会话阶段承载PPP报文
PPPoE作为宽带网接入的一种有效方法,不但可以防止IP被盗用,还有利于开展多服务、速率限制和按时按流量计费等多方面的应用。
习题3:
该题主要考查对CSMA/CD和CSMA/CA协议,以及无线网络中“隐藏站”问题的理解程度。
习题4:
XINU操作系统源代码ether\lance目录下存放的是AMD7990Lance以太网控制器驱动实现程序源代码,其中ethdemux函数实现了该控制器接收到以太帧后所要进行的多路分解操作。
该函数首先进行一些检查,然后进行数据帧的复制,并最终转入ni_in()函数,进行网络接口层的多路分解。
/*ethdemux.c-ethdemux*/
#include
#include
#include
/*--------------------------------------------------------------------------------------------------
*ethmudex-选择一个端口发送一个传入的数据报(ETHER端或者其他)
*-------------------------------------------------------------------------------------------------
*/
/*首先检查来自网络的数据帧的正确性,然后申请缓冲区以存储数据帧,最后将数据帧交由ni_in()函数处理*/
intethdemux(etptr,bn)
structetblk*etptr;/*以太网控制块描述*/
intbn;
{
structbre*pbre;
structle_md*pmd;/*消息描述符*/
structotblk*otptr;
structep*pep;/*以太网的帧结构*/
intnoth,readlen,errs,ifnum;
char*dest;
ifnum=etptr->etintf;/*端口号*/
pbre=&etptr->etbrr[bn];
pmd=pbre->pmd;
errs=pmd->lmd_flags&(RMD_FRAM|RMD_OFLO|RMD_CRC|RMD_BUFF);
if(errs!
=0){
if(errs&RMD_FRAM)
kprintf("ethread:
framingerror\n");
if(errs&RMD_OFLO)
kprintf("ethread:
bufferoverflow\n");
if(errs&RMD_CRC)
kprintf("ethread:
CRCerror\n");
if(errs&RMD_BUFF)
kprintf("ethread:
don'townnextbuffer\n");
gotodrop;
}
readlen=pmd->lmd_mcnt;/*消息的长度(实际长度)*/
if(readlen>(EP_DLEN+18))/*长度是否合法*/
gotodrop;
pep=(structep*)nbgetbuf(Npool);/*申请帧缓冲区*/
if(pep==0){/*申请失败*/
if(ifnum>=0&&ifnumnif[ifnum].ni_idiscard++;
gotodrop2;
}
blkcopy(&pep->ep_eh,pbre->buf,readlen-EP_CRC);
/*将网卡缓冲区中的信息复制到帧缓冲区*/
pmd->lmd_flags=LMD_OWN;/*将使用权还给以太网卡*/
pbre->flags=0;/*标志位清零*/
#ifNoth>0/*其他设备端口*/
dest=(char*)pep->ep_dst;
for(noth=0;nothotptr=etptr->etoth[noth];
if(otptr==0||!
otptr->ot_valid)
continue;
if(blkequ(dest,otptr->ot_paddr,EP_ALEN)||
blkequ(dest,otptr->ot_baddr,EP_ALEN))
break;
}
if(noth!
=Noth)
ifnum=otptr->ot_intf;
#endif
if(ifnum<0)/*端口号是否合法*/
returnfreebuf(pep);
if(nif[ifnum].ni_state!
=NIS_UP){/*端口是否处于已连接状态*/
nif[ifnum].ni_idiscard++;
returnfreebuf(pep);
}
pep->ep_type=net2hs(pep->ep_type);/*将帧类型字节序转换为本机字节序*/
/*ni_in函数可以根据帧类型来判断多路分解*/
ni_in(&nif[ifnum],pep,readlen);/*调用ni_in函数来处理数据帧*/
returnOK;
drop:
if(ifnum>=0&&ifnumnif[ifnum].ni_ierrors++;
drop2:
pmd->lmd_flags=LMD_OWN;/*交还使用权*/
pbre->flags=0;
returnSYSERR;
}
流程图如下:
习题5:
dot2ip()函数和ip2dot()函数实现了字符串形式的点分十进制格式的IP地址与32位IP地址格式之间的相互转换。
/*dot2ip.c-dot2ip*/
#include
#include
#include
/*------------------------------------------------------------------------
*dot2ip-将字符串形式的点分十进制格式IP地址转换为一个没有小数点的IP地址
*------------------------------------------------------------------------
*/
dot2ip(constchar*pdot)
/*参数pdot是一个指向字符数组的指针,字符数组每个单元存储IP地址的一个字节:
[192][.][168][.][101][.][1]*/
{
IPaddrip;/*IPaddr是个无符号长整型*/
unsignedchar*p;/*定义一个指向字符数组的指针,但此指针并没有指向真正的内存空间*/
inti;
ip=0;
p=(unsignedchar*)&ip;/*使字符数组指针p指向起始地址是&ip的内存单元*/
for(i=0;pdot&&*pdot&&i*p++=atoi(pdot);/*将IP地址的一个字节保存到指针p所指向的内存单元中*/
if(pdot=index(pdot,'.'))/*判断pdot是否指向字符数组的最后一个单元,并且跳过[.]单元*/
++pdot;
else
break;
}
returnip;/*返回存储IP地址首单元的地址*/
}
/*ip2dot.c-ip2dot*/
#include
#include
#include
/*------------------------------------------------------------------------
*ip2dot-将一个没有小数点的IP地址转换为字符串形式的点分十进制格式IP地址
*------------------------------------------------------------------------
*/
char*ip2dot(char*pdot,IPaddrip)/*pdot指向一个字符数组,用于存储转换后的IP地址;IP是没有小数点的IP地址的首地址*/
{
char*pch=pdot;
inti;
sprintf(pch,"%u",((char*)&ip)[0]&0xff);/*将IP地址第一个字节的值存入pch所指向的字符数组的第一个单元中*/
pch+=strlen(pch);/*pch跳过长度为strlen(pch)的内存单元,即指向下一个单元*/
for(i=1;isprintf(pch,".%u",((char*)&ip)[i]&0xff);/*将[.]及IP地址的下一个字节保存到pch指向的单元*/
pch+=strlen(pch);/*pch跳过长度为strlen(pch)的内存单元,即指向下一个单元*/
}
*pch=NULL;/*指针置空*/
returnpdot;/*返回指向字符串形式的点分十进制格式IP地址的首地址*/
}
习题6:
Netmatch()函数用于判断一个IP地址是否属于某个网络,netnum()函数用于判断一个IP地址的类别。
这两个函数都是采用C语言的位操作来完成的。
/*netmatch.c-netmatch*/
#include
#include
#include
/*------------------------------------------------------------------------
*netmatch–检查目的IP地址是否在此网络中
*------------------------------------------------------------------------
*/
Boolnetmatch(IPaddrdst,IPaddrnet,IPaddrmask,Boolislocal)
{
if((dst&mask)!
=(net&mask))/*IP地址跟子网掩码进行与运算的结果就是网络号,以此来判断dst在不在该网络上*/
returnFALSE;
/*
*localsrcsshouldonlymatchunicast(单一传播)addresses(hostroutes)
*/
if(islocal)/*判断是否来自于本地网络*/
if(isbrc(dst)||IP_CLASSD(dst))//如果dst是广播地址或是组播地址*/
returnmask!
=ip_maskall;
/*如果是来自于本地网络并且是广播地址或是组播地址,那么发送该广播帧的主机就不需要接收此广播帧,于是将自己置成不匹配此网络,就不会再收到此广播帧了*/
returnTRUE;
}
/*netnum.c-netnum*/
#include
#include
#include
/*------------------------------------------------------------------------
*netnum-用来得到某个IP地址的网络号
*------------------------------------------------------------------------
*/
netnum(IPaddripa)
{
IPaddrmask=~0;/*初始化为0*/
if(IP_CLASSA(ipa))mask=hl2net(0xff000000);/*得到A类地址的子网掩码255.0.0.0*/
if(IP_CLASSB(ipa))mask=hl2net(0xffff0000);/*得到B类地址的子网掩码255.255.0.0*/
if(IP_CLASSC(ipa))mask=hl2net(0xffffff00);/*得到C类地址的子网掩码255.255.255.0*/
returnipa&mask;/*得到网络号,即网络地址*/
}
第3章习题解答参考思路
习题1:
本题主要考查对ARP软件整体结构的理解程度,并帮助学生梳理ARP软件中函数之间的关系,从而更好地掌握ARP软件中函数的功能和处理机制。
详细描述请参照3.3节。
习题2:
本题主要考查对ARP报文处理算法的理解程度,并帮助学生进一步理解ARP报文处理算法。
报文处理算法可以概括为三个部分:
当报文交付给arp_in()函数时,该算法首先确认该报文是否为合法报文及特征是否与接口相符;然后查询ARP缓冲区表项,若不存在对应表项且确认该报文是发往本机,则直接创建新表项,再根据该报文对表项进行修改操作;最后根据该ARP报文是否为ARP请求来决定下一步操作,构造一个ARP应答报文或清理该ARP报文。
ARP报文处理算法的利弊分析如下:
在正常操作下,这是一种很有效率的处理算法,简单明了快捷。
但是由算法分析可知,arp_in()函数“不计后果”地使用当前处理的ARP报文中的<发送方协议地址,发送方物理地址>创建新缓冲区或者修改已存在的缓冲表项,没有使用任何保护手段或者措施。
ARP攻击者很容易利用这一缺陷,发送ARP欺骗报文。
习题3:
主机发送IP数据报是通过调用netwrite()函数来实现的,因此分析netwrite()函数即可了解IP数据报的发送过程。
详细描述请参考3.5节。
习题4:
Arpalloc.c代码如下:
/*--------------------------------------------------------------------------------------------------
*在ARP缓冲区表中分配一个表项
*--------------------------------------------------------------------------------------------------
*/
structarpentry*arpalloc()
{
/*缓冲区表中所指的当前表项,这里采用的是循环队列的数据结构,故需要记录当前表项所处的位置*/
staticintaenext=0;
struct