IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)

一、OSI模型与TCP/IP协议栈

1.1 OSI 7层模型:

应用层:
功能:用户接口,文件传输、电子邮件、虚拟终端、文件服务
设备:网关
协议:HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet

表示层:
功能:数据的表示,压缩和加密
设备:网关
协议:无

会话层:
功能:会话的建立和结束
设备:网关
协议:无

传输层:
功能:提供端对端的接口
设备:网关
协议:TCP UDP

网络层:
功能:为数据报选择路由,寻址
设备:路由器
协议:IP、ICMP、IGMP、RIP

数据链路层:
功能:传输有地址的帧与错误校验功能
设备:交换机、网桥、网卡
协议:PPP、ARP、MTU、RARP、SLIP、CSLIP

物理层:
功能:传输比特流,以二进制数据形式在物理媒体上传输数据
设备:集线器、中继器
协议:IEEE802、IEEE802.2、ISO2110

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第1张图片

1.2 数据封装过程:

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第2张图片
IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第3张图片
IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第4张图片
IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第5张图片
图片来源:https://blog.csdn.net/shimazhuge/article/details/5382725?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-5-5382725-blog-78396507.235v29pc_relevant_default_base3&spm=1001.2101.3001.4242.4&utm_relevant_index=8

1.3 TCP/IP 4层模型:

应用层:
功能:用户接口,文件传输、电子邮件、虚拟终端、文件服务
设备:网关
协议:HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet

传输层:
功能:提供端对端的接口
设备:网关
协议:TCP UDP

网络层:
功能:为数据报选择路由,寻址
设备:路由器
协议:IP、ICMP、IGMP、RIP

数据链路层:
功能:传输有地址的帧与错误校验功能
设备:交换机、网桥、网卡
协议:PPP、ARP、MTU、RARP、SLIP、CSLIP

二、报文解析

2.1 IP报文

2.1.1 IP报文格式

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第6张图片
IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第7张图片

2.1.2 IP报文解析及校验和计算:

十六进制加法计算器:
https://www.9321.cn/digital-computation/hex-addition-calculator.php

crc校验:http://www.ip33.com/crc.html

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第8张图片

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第9张图片

2.2 UDP报文

2.1.1 UDP报文格式:

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第10张图片

2.1.2 UDP报文解析及校验和计算:

UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。伪首部+UDP首部+数据一起计算校验和。

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第11张图片

2.3 TCP报文

2.3.1 TCP报文格式

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第12张图片
1> 16位源端口号,2个字节。客户端通常使用系统自动选择的临时端口号。
2> 16位目的端口号,2个字节。服务器的端口号。
3> 32位序号,4个字节。A与B连接后发送第一个报文段,序号值被系统分配随机一个值S,后续报文段的序号值为S + 偏移值(该报文段第一个字节在整个字节流中第几个字节,例如,某个TCP报文段传送的数据是字节流中的第1025~2048字节,那么该报文段的序号值就是ISN+1025)
4> 32位确认号,4个字节。用作对另一方发送来的TCP报文段的响应。其值是收到的TCP报文段的序号值加1
5> 4位头部长度,表示有多少个32位字(4字节),4位最大值是15,所以头部最长60字节。
6> 6位保留。
7> 6位,ACK: 表示确认号是否有效。 PSH: 提示接收端应用程序应该立即从TCP接收缓冲区中读走数据。RST: 表示要求对方重新建立连接。 SYN: 表示请求建立一个连接。FIN:表示通知对方本端要关闭连接了。URG(紧急位):设置为1时,首部中的紧急指针有效;为0时,紧急指针没有意义。
8> 16位窗口大小,2个字节。告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。最大位65535字节。窗口大小为0时候,说明数据被截断
9> 16位校验和,2个字节。由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。
10> 16位紧急指针,2个字节。
11> TCP头部选项,最多40字节。因为TCP头部最长60字节(其中还包含前面讨论的20字节的固定部分)

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第13张图片

2.3.2 TCP三次握手和四次挥手过程

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第14张图片
IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第15张图片
IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第16张图片

2.4 ICMP报文

2.4.1 ICMP报文格式

ping使用的是 ICMP 的请求回显/回显应答类型的报文,它的内容包括标识符、序列号以及回显数据3部分,报文大小默认为 64 字节(header的8字节+body的56字节)。

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第17张图片

2.4.2 ICMP报文解析及校验和计算

ICMP校验和:
生成:先将校验和置为0,然后将ICMP报文的header+body按16bit分组求和。如果结果溢出,则将高16位和低16位求和,直到高16位为0。最后求反就是检验和的值。

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)_第18张图片

三、相关代码分享:

BOOL CSerialDlg::TestPing()
{
    string sDesIP = "202.108.22.5";
    int nDestIP[4];
    int k,l,mm;
    char DestIP0[2];
    char DestIP1[2];
    char DestIP2[2];
    char DestIP3[2];
	CString strText;
    CString strVersion;
    CString strPath = _T("FM100M001.ini");
    BYTE temp[256];
    memset(temp, 0x00, 256);
    m_PPPPacket.bRecPing = FALSE;

    AddText(_T("Ping测试开始"));
    if(!GetInitFileStrings(strPath, _T("PPP"), _T("Ping"), sDesIP))
    {
        ffprint("获取配置文件Ping的IP失败");
    }
    ffprint("ping sDesIP:%s", sDesIP.c_str());
            
    //Dest IP
    vector vec = CStringUtils::Split(sDesIP, _T("."));
    if(vec.size() >= 4)
    {
        for(int i = 0; i < 4; i++)
        {
            nDestIP[i] = atoi(vec[i].c_str());
        }
        DectoHex(nDestIP[0], DestIP0, 1);
        DectoHex(nDestIP[1], DestIP1, 1);
        DectoHex(nDestIP[2], DestIP2, 1);
        DectoHex(nDestIP[3], DestIP3, 1);
        
        temp[0] = DestIP0[0];	
        temp[1] = DestIP1[0];
        temp[2] = DestIP2[0];
        temp[3] = DestIP3[0];
    }

    //数据长度
	CString m_senddata = _T("AT");
	temp[4] = strlen(m_senddata)>>8;
	temp[5] = strlen(m_senddata)&0x00ff;

	//数据
	CString strData = Ascii2Hex(m_senddata);
    char DataHex[256] = {0};
    String2Hex(strData, DataHex);
    
	mm = strlen(m_senddata)+6;
	l = 0;
	for (k=6; k 0)
        {
            strText.Format(_T("Ping %s 中..."), sDesIP.c_str());
            AddText(strText);
          
            int iRet = SendHex(m_PPPPacket.PacketTx, STATE_NCP_PING, m_PPPPacket.TxLen, 10000);
            if (iRet != -1)
            {
                if(m_PPPPacket.bRecPing)
                {
                    strText.Format(_T("Ping %s通过,网络正常."), sDesIP.c_str());
                    AddText(strText, 1);
                    PushResult(strText, strText.GetLength(), 1);
                    return TRUE;
                }
            }
        } 
    }

    strText.Format(_T("Ping %s不通过,网络异常."), sDesIP.c_str());
    AddText(strText, 2, true);
	PushResult(strText, strText.GetLength(), 2);

	return FALSE;
}

BOOL CSerialDlg::TestUdp()
{
    CString strText;

    //Dest IP
    CString m_ipOut0;
	CString m_ipOut1;
	CString m_ipOut2;
	CString m_ipOut3;
    BYTE temp[256];
    int k,l,j;
	memset(temp,0x00,256);

    m_ipOut0 = _T("120");			
	m_ipOut1 = _T("42");
	m_ipOut2 = _T("46");
	m_ipOut3 = _T("98");

    int nDestIP0 = atoi(m_ipOut0);
    int nDestIP1 = atoi(m_ipOut1);
    int nDestIP2 = atoi(m_ipOut2);
    int nDestIP3 = atoi(m_ipOut3);

    char DestIP0[2];
    char DestIP1[2];
    char DestIP2[2];
    char DestIP3[2];
    DectoHex(nDestIP0, DestIP0, 1);
    DectoHex(nDestIP1, DestIP1, 1);
    DectoHex(nDestIP2, DestIP2, 1);
    DectoHex(nDestIP3, DestIP3, 1);

    temp[0] = DestIP0[0];	
	temp[1] = DestIP1[0];
	temp[2] = DestIP2[0];
	temp[3] = DestIP3[0];
    
    
    //Src Port and Dest Port
    CString m_srcport = _T("4321");
    CString m_desport = _T("7100");
    temp[4] = atoi(m_srcport)>>8;			//source port msb
	temp[5] = atoi(m_srcport)&0x00ff;		//source port lsb
	temp[6] = atoi(m_desport)>>8;			//destination port msb
	temp[7] = atoi(m_desport)&0x00ff;	    //destination port lsb


    //length
    CString m_senddata = _T("UDP Test");
	j = strlen(m_senddata) + 8;
	temp[8] = j>>8;	                        //the length of send udp data's msb
	temp[9] = j&0x00ff;	                    //the length of send udp data's lsb
	temp[10] = 0;
	temp[11] = 0;


    //Data
    CString strData = Ascii2Hex(m_senddata);
    char DataHex[256] = {0};
    String2Hex(strData, DataHex);
    
    l=0;
	for (k=12; k 0)
    {
        std::string hexStr2 = HexToString(m_PPPPacket.PacketTx, m_PPPPacket.TxLen);
                                    
        strText.Format(_T("发送:%s"), hexStr2.c_str());
        AddText(strText);
        
        if(m_serial.SendDataFromSerial(m_PPPPacket.PacketTx, m_PPPPacket.TxLen))
        {
            CString sMsg = _T("UDP测试数据已发送, 确认UDP报文是否被接收.\r\n(点击确认按钮继续下面测试,点击取消按钮结束测试.)");
            BOOL bResult = FALSE;
            int msgboxID = MessageBox(sMsg, _T("UDP发送测试"), MB_OKCANCEL | MB_ICONQUESTION);
            switch(msgboxID)
            {
                case IDCANCEL:
                    bResult = FALSE;
                break;
                case IDOK:
                    bResult = TRUE;
                break;
            }

            if(bResult)
            {
                strText = _T("UDP发送测试通过");
		        AddText(strText, 1);
		        PushResult(strText, strText.GetLength(), 1);
                return TRUE;
            }
            else
            {
                strText = _T("UDP发送测试失败");
                AddText(strText, 2, true);
                PushResult(strText, strText.GetLength(), 2);
                return FALSE;
            } 
        }
    }

    strText = _T("UDP数据发送失败");
    AddText(strText, 2, true);
	PushResult(strText, strText.GetLength(), 2);
   
    return FALSE;
}

PPP_Packet.h

/* ***************************************************************
 * Filename:            Packet.h
 *  @Description:
 *         Packet Creat Check
 *  @Author: ybLin
 * ***************************************************************/
#ifndef __PPP_PACKET_H__
#define __PPP_PACKET_H__

#include 
#include "crc.h"
#include  

#define PPP_FRAME_FLAG		0x7E 	 	//标识字符 
#define PPP_FRAME_ESC		0x7D 	 	//转义字符 
#define PPP_FRAME_ENC		0x20 	 	//编码字符 
#define MAX_RECV_PKT_SIZE	256
#define MIN_RECV_PKT_SIZE 	12
#define PROTOCOL_LCP		0xC021      //LCP协议
#define PROTOCOL_IPCP	    0x8021      //NCP协议:IPCP
#define PROTOCOL_IP		    0x0021      //IP协议
#define PROTOCOL_PAP		0xC023      //PAP认证

extern BYTE g_LcpFirstReq[256];
extern BYTE g_TermReq[256];
extern BYTE g_NcpFirstReq[256];
extern std::string HexToString(const BYTE *pBuffer, size_t iBytes);
extern void DectoHex(int dec, char *hex, int length);
extern unsigned long HextoDec(const unsigned char *hex, int length); 
extern CString Ascii2Hex(CString strASCII);
extern char Char2Hex(char ch);
extern int String2Hex(CString str, char* SendOut);

//执行过程
typedef enum PPP_STATE
{
    PPP_STATE_INIT = 0,
    PPP_STATE_LCP_PERIOD,
    PPP_STATE_LCP_PASS,
    /*
    PPP_STATE_PAP_START,
    PPP_STATE_PAP_PASS,*/
    PPP_STATE_NCP_PERIOD,
    PPP_STATE_NCP_NAK,
    PPP_STATE_PPP_PASS,
    PPP_STATE_IP_START,
    PPP_STATE_TERM_LINK
}PPP_STATE_E;

//编码值
typedef enum PPP_CODE
{
    PPP_CODE_REQ = 1,   				//配置请求
    PPP_CODE_ACK,       				//接受配置
    PPP_CODE_NAK,       				//配置请求接受,其他拒绝
    PPP_CODE_REJ,       				//配置请求不认识,或不被接受
    PPP_CODE_TERM_LINK, 				//终止链接
    PPP_CODE_TERM_ACK,  				//终止确认
    PPP_CODE_CODE_REJ,
    PPP_CODE_PROTOCAL_REJ,
    PPP_CODE_ECHO_REQ,
    PPP_CODE_ECHO_REP,
    PPP_CODE_DISCARD_REQ,
    PPP_CODE_IDENTIFICATION,
    PPP_CODE_TIME_REM
}PPP_CODE_E;

//报文解析返回
enum PPP_OPERATE_STATE
{
	PPP_OPERATE_ERROR = -1,
	PPP_OPERATE_NORMAL,
	PPP_OPERATE_NEED_SEND
};

//选项值
typedef struct PPP_OPTION
{
    BYTE bType;
	BYTE bLength;
	BYTE bData[64];
	BOOL bReject;

}PPP_OPTION_T;

//IP头
typedef struct IP_HEADER
{
    BYTE Version;	//4bits
	BYTE IHL;		//4bits
	BYTE Service;
	unsigned short TotalLength;
	unsigned short Identification = 0x0000;
	BYTE FLAG;
	unsigned short FlagFrag;	
	BYTE TTL;
	BYTE protocol;
	BYTE HeaderSum;	
	BYTE SrcIP[4];	
	BYTE DesIP[4];
}IP_HEADER_T;

//ICMP头
typedef struct ICMP_HEADER
{
    BYTE type;
	BYTE code;
	unsigned short sum;
	unsigned short identifier;
	unsigned short sequence = 0x0000;
}ICMP_HEADER_T;

//IP
#define		IP_ICMP			0x01
#define		IP_TCP			0x06
#define		IP_UDP			0x11

//ICMP
#define		ICMP_PING		0x08
#define		ICMP_PINGREPLY	0x00



class CPacket  
{
public:
    CPacket();
    virtual ~CPacket();

    //初始化
    void InitPacket();
    
    //解析报文
    int Parsepkt(BYTE *pPkt, int nLen); 

    //检测配置选项
    void CheckOption(WORD wProType, BYTE CodeVal, BYTE* pOption);

    //创建PPP报文
    void CreatePPPPkt(WORD wProType, BYTE CodeVal, BYTE* pPkt, bool bActive = FALSE);
    
    //创建IP报文
    void CreateIpPkt(BYTE protocal, BYTE type, BYTE *temp);
 
private:
    //字符编码
    int CharacterEncode(int iLen);

    //转义编码
    int TransferEncode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt);
    //转义解码
    int TransferDecode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt);

    //日志输出
    void WriteLog(CString temp);


public:
	WORD wProtocolType; 		//协议类型 2个字节 
	BYTE PktID;		    		//包 ID 
	BOOL bReject;				//判断包是 ACK     或者 REJ
	BYTE CurState;              //PPP状态
    BYTE SrcIP[4];              //源动态IP
    int nOptionNum;             //配置选项数量
    BYTE PacketTx[256];         //发送包
	BYTE PacketTx1[256];	    //发送包
	BYTE PacketRx[256];         //接受包
	int TxLen;                  //发送包长度
	int RxLen;                  //接受包长度

    BOOL bRecPing;              //是否收到ping回复
	PPP_OPTION_T option[8];     //选项值
	IP_HEADER_T IP_header;
	ICMP_HEADER_T ICMP_header;
    int m_nNcpAckNum;
	
	CCRC m_crc;
};
#endif 

PPP_Packet.cpp

/* ***************************************************************
 * Filename:            Packet.cpp
 *  @Description:
 *         Packet Creat Check
 *  @Author: ybLin
 * ***************************************************************/
#include "stdafx.h"
#include "PPP_Packet.h"
#include "Common.h"


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

int auth_skipped=1;
int block_ipcp_req= 0;

BYTE g_LcpFirstReq[256] = {0x7E, 0xFF, 0x03, 0xC0, 0x21, 0x01, 0x01, 0x00, 0x0A, 0x02, 0x06, 0x00, 0x00, 
                           0x00, 0x00, 0x58, 0x7B, 0x7E};
BYTE g_NcpFirstReq[256] = {0x7E, 0xFF, 0x03, 0x80, 0x21, 0x01, 0x03, 0x00, 0x0A, 0x03, 0x06, 0x00, 
                           0x00, 0x00, 0x00, 0xE9, 0xB3, 0x7E};

BYTE g_TermReq[256] = {0x7E, 0xFF, 0x03, 0xC0, 0x21, 0x05, 0x01, 0x00, 0x04, 0x3D, 0xC7, 0x7E};

char hextbl[] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };

//Common Api
std::string HexToString(const BYTE *pBuffer, size_t iBytes)
{
   std::string result;

   for (size_t i = 0; i < iBytes; i++)
   {
       BYTE c ;
       BYTE b = pBuffer[i] >> 4;
       if (9 >= b)
       {
           c = b + '0';
       }
       else
       {
           c = (b - 10) + 'A';
       }

       result += (TCHAR)c;

       b = pBuffer[i] & 0x0f;

       if (9 >= b)
       {
           c = b + '0';
       }
       else
       {
           c = (b - 10) + 'A';
       }

       result += (TCHAR)c;
       if (i != (iBytes-1))
           result += " ";
   }
   return result;
}

void DectoHex(int dec, char *hex, int length) 
{ 
	for(int i=length-1; i>=0; i--) 
	{ 
		hex[i] = (dec%256)&0xFF; 
		dec /= 256; 
	} 
}

unsigned long HextoDec(const unsigned char *hex, int length) 
{ 
	unsigned long rslt = 0; 
	for(int i=0; i= '0') && (ch <= '9'))
		return ch - 0x30;
	if ((ch >= 'A') && (ch <= 'F'))
		return ch - 'A' + 10;
	if ((ch >= 'a') && (ch <= 'f'))
		return ch - 'a' + 10;
	else
		return(-1);
}

//字符串转换为16进制数据
int String2Hex(CString str, char* SendOut)
{
	int hexdata, lowhexdata;
	int hexdatalen = 0;
	int len = str.GetLength();

	for (int i = 0; i < len;)
	{
		char lstr, hstr = str[i];
		if (hstr == ' ' || hstr == '\r' || hstr == '\n')
		{
			i++;
			continue;
		}
		i++;
		if (i >= len)
			break;
		lstr = str[i];
		hexdata = Char2Hex(hstr);
		lowhexdata = Char2Hex(lstr);
		if ((hexdata == 16) || (lowhexdata == 16))
			break;
		else
			hexdata = hexdata * 16 + lowhexdata;
		i++;
		SendOut[hexdatalen] = (char)hexdata;
		hexdatalen++;
	}
	return hexdatalen;

}

//Packet
CPacket::CPacket()
{
    InitPacket();
}

CPacket::~CPacket()
{
}

void CPacket::InitPacket()
{
    CurState = PPP_STATE_INIT;
	TxLen = 0;
	bReject = FALSE;
	PktID = 0x01;
    nOptionNum = 0;

	for(int i=0; i<8; i++)
	{
		option[i].bReject = TRUE;
		memset(option[i].bData, 0x0, 64);
	}
	memset(PacketTx,0x0,256);
	memset(SrcIP,0x00,4);
}

int CPacket::Parsepkt(BYTE *pPkt, int nLen)
{
	BYTE CodeVal;
	char tempbuf[100];
    memset(PacketRx, 0x00, 256);
	TxLen = 0;
    int nRet = PPP_OPERATE_NORMAL; 

    if(nLen < MIN_RECV_PKT_SIZE)
    {
        ffprint("nLen < MIN_RECV_PKT_SIZE nLen:%d", nLen);
        nRet = PPP_OPERATE_ERROR;
		return nRet;
    }

    RxLen = TransferDecode(pPkt, nLen, PacketRx);
    if(RxLen < MIN_RECV_PKT_SIZE)
	{
		ffprint("RxLen < MIN_RECV_PKT_SIZE RxLen:%d", RxLen);
        nRet = PPP_OPERATE_ERROR;
		return nRet;
	}

    std::string hexStr2 = HexToString(PacketRx, RxLen);
    ffprint("Parsepkt decode hexStr:%s", hexStr2.c_str());
    
	wProtocolType = PacketRx[3]*256 + PacketRx[4];
 
	switch(wProtocolType)
    {
	    case PROTOCOL_LCP:
		{
			CodeVal = PacketRx[5]; //获取编码值
			PktID = PacketRx[6];
			switch(CodeVal)
            {
    			case PPP_CODE_REQ:

    				CheckOption(wProtocolType, CodeVal, PacketRx);

                    if(bReject == TRUE)
                    {
                        CodeVal = PPP_CODE_REJ;
                    }
                    else 
                    { 
                        CodeVal = PPP_CODE_ACK;
                    }         
    				CreatePPPPkt(wProtocolType, CodeVal, PacketRx); 	
                    nRet = PPP_OPERATE_NEED_SEND;
    				break;
    			case PPP_CODE_ACK:
                    if(CurState == PPP_STATE_LCP_PASS)
                    {
                        //无认证,直接发送NCP请求
                        CurState = PPP_STATE_NCP_PERIOD;
                        CreatePPPPkt(PROTOCOL_IPCP, PPP_CODE_REQ, g_NcpFirstReq, TRUE);
                        nRet = PPP_OPERATE_NEED_SEND;
                        m_nNcpAckNum = 0;
                    }
    				break;
    			case PPP_CODE_NAK:
    				break;
    			case PPP_CODE_REJ:
    				break;
    			default:
    				break;
			}
			
			break;
		}
	    case PROTOCOL_IPCP:  //无转义
    		CodeVal = PacketRx[5];
    		PktID = PacketRx[6];
    		switch(CodeVal)
            {
        		case PPP_CODE_REQ:
                    ffprint("PROTOCOL_IPCP PPP_CODE_REQ");
                
                    CurState = PPP_STATE_NCP_PERIOD;
        		    CreatePPPPkt(wProtocolType, PPP_CODE_ACK, PacketRx);
                    nRet = PPP_OPERATE_NEED_SEND;
                    m_nNcpAckNum++;
        			break;
        		case PPP_CODE_ACK: //最终受到确认后,NCP通过
                    ffprint("PROTOCOL_IPCP PPP_CODE_ACK");
                
        			if (CurState < PPP_STATE_PPP_PASS)	
                        CurState = PPP_STATE_PPP_PASS;

                    m_nNcpAckNum = 0;

        			break;
        		case PPP_CODE_NAK:
                    ffprint("PROTOCOL_IPCP PPP_CODE_NAK");
                
        			CheckOption(wProtocolType, CodeVal, PacketRx);
                
        			if (CurState < PPP_STATE_NCP_NAK && bReject == false) 
                        CurState = PPP_STATE_NCP_NAK;

        			CreatePPPPkt(wProtocolType, PPP_CODE_REQ, PacketRx);
                    nRet = PPP_OPERATE_NEED_SEND;
        			break;
        		default:
        			break;
    		}
    		break;
    case PROTOCOL_IP:    
		IP_header.protocol = PacketRx[14];
        /*
		int k;
		k=16+1;
		IP_header.SrcIP[0] = pPkt[k++];
		IP_header.SrcIP[1] = pPkt[k++];
		IP_header.SrcIP[2] = pPkt[k++];
		IP_header.SrcIP[3] = pPkt[k++];
		IP_header.DesIP[0] = pPkt[k++];
		IP_header.DesIP[1] = pPkt[k++];
		IP_header.DesIP[2] = pPkt[k++];
		IP_header.DesIP[3] = pPkt[k++];*/

		switch(IP_header.protocol)
		{
    		case IP_ICMP:
    			ICMP_header.type = PacketRx[25];
                ffprint("PROTOCOL_IP protocol:%02x  type:%02x", IP_header.protocol, ICMP_header.type);
    			switch (ICMP_header.type)
    			{
        			case ICMP_PING:
        				//CreateIpPkt(IP_ICMP, ICMP_PINGREPLY, pPkt+5);
        				break;
        			case ICMP_PINGREPLY:
        				bRecPing = true;
        				break;
        			default:
        				break;
    			}
    			break;
    		case IP_UDP:
    			break;
    		default:
    			break;
		}
		break;

	default:
		break;
	}
	return nRet;
}

void CPacket::CheckOption(WORD wProType, BYTE CodeVal, BYTE* pOption)
{
	WORD wSize, wStart;
	int i=0, j=0, k;

	bReject = FALSE;
	wStart = 9; //数据位从这里开始
	wSize = pOption[7]*256 + pOption[8] + 8;            //8:length+framebegin(3)+protocol(2)+checksum(2)+frameend(1)
	if (wSize > MAX_RECV_PKT_SIZE - 8)                  //truncate packet if larger than buffer
        wSize = MAX_RECV_PKT_SIZE - 8;     

    //获取配置项
	for(k=0; k<8; k++)
	{
		option[k].bReject = TRUE;
		memset(option[k].bData, 0x0, 64);
	}

	while(wStart < wSize-3)
	{
		option[j].bType = pOption[wStart++];
		option[j].bLength = pOption[wStart++];
		for (i = 0; i 0 && option[i].bType <= 29)
				{
					switch(option[i].bType)
					{
                        //最大-接收-单元
						case 1:		
							option[i].bReject = FALSE;
							break;

                        //异步-控制-字符-映射
						case 2:		
							option[i].bReject = FALSE;
							break;

                        //鉴定-协议
						case 3:		
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;

                        //魔术字
						case 5:		
							option[i].bReject = FALSE;
							break;

                        //协议域压缩
						case 7:		
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;

                        //地址和控制域压缩
						case 8:		
							option[i].bReject = TRUE;
						    bReject = TRUE;
							break;

						default:
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
					}
				}
			}
			break;
		}

		case PROTOCOL_IPCP:
			for(i=0; i0 && option[i].bType<5)||
                    (option[i].bType>=129 && option[i].bType<=132))
				{
					switch(option[i].bType)
					{
						case 1:		                                //静态IP配置
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
						case 2:		                                //IP压缩协议
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
						case 3:		                                //动态IP配置
							option[i].bReject = FALSE;
							if (CodeVal == PPP_CODE_NAK)
							{
								ffprint("NAK option[i].bLength:%d", option[i].bLength);
								for (k=0;k> 1) ^ 0x8408;        // 0x8408 = reverse 0x1021
            else
                crc = (crc >> 1);
        }
    }
    return ~crc;                // crc^Xorout
} 


void CPacket::CreatePPPPkt(WORD wProType, BYTE CodeVal, BYTE* pPkt, bool bActive)
{
	int i,j,k;
	WORD wLen, whigh = 0, wlow = 0; //header checksum;
	int iHeadpos;
	WORD wChecksum;
    int nLenthPos;
	memset(PacketTx, 0x00, 256);  //有转义的包

	i=0;
	PacketTx[i++] = 0x7e;      //帧首个字节
	switch(wProType)
	{
		case PROTOCOL_LCP:
			switch(CodeVal)
			{
				case PPP_CODE_REQ:
					for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                 //frame head and protocol
					}
					
					PacketTx[i++] = CodeVal;                   //code
					PacketTx[i++] = PktID;                     //递增ID
					nLenthPos = i;                             //get the length postion
					i+=2;

                    if(bActive)                                //主动发送,数据域直接拷贝
                    {
                        while(pPkt[i] != 0x7e)                      
    					{
    						PacketTx[i] = pPkt[i];
    						i++;
    					}
    					i-=2;
    					PacketTx[i]='\0';
    					PacketTx[i+1]='\0';
                    }
                    else
                    {
                        //LCP配置项
    					for(k=0; k>8) & 0x00ff);

    if(wProType == PROTOCOL_LCP)
    {
        i = CharacterEncode(i);
    }
    
    PacketTx[i] = 0x7e;//and framing end 0x7e
	TxLen = i+1;
	PktID++;
	bReject = FALSE;
}

void CPacket::CreateIpPkt(BYTE protocal, BYTE type, BYTE *temp)
{
	int i,j,k;
    int nLenthPos, nHeadcheckpos, nIcmpcheckpos;
	WORD wLen,whigh = 0x0000,wlow = 0x0000;//header checksum;
	int iHeadpos,TTLpos;
	WORD wChecksum;
	
	memset(PacketTx, 0x00, 256);

    //7E FF 03 00 21
	i = 0;
	PacketTx[i++] = 0x7e;//frame header

	PacketTx[i++] = 0xff;
	PacketTx[i++] = 0x03;

    PacketTx[i++] = 0x00;
	PacketTx[i++] = 0x21;
	iHeadpos = i;

    //版本(4) + 首部长度(4) + 区分服务(8)
	PacketTx[i++] = 0x45;   //version and header length
	PacketTx[i++] = 0x00;   //service

    //总长度
	nLenthPos = i;			//total length position
	i += 2;

    //标识
    PacketTx[i++] = 0x00;
    PacketTx[i++] = 0x05;

    //标志(8) + 片偏移(8)
    PacketTx[i++]=0x00;
	PacketTx[i++]=0x00;

    //生存时间(8) + 协议(8)
	TTLpos=i;
	PacketTx[i++] = 0x80;//TTL
	PacketTx[i++] = protocal;//0x11:UDP 0x01:ICMP

    //IP 首部校验和
	nHeadcheckpos=i;
	PacketTx[i++]=0x00;//header checksum
	PacketTx[i++]=0x00;//header checksum

    //源IP
	for(j=0;j<4;j++)
	{
		PacketTx[i++]=SrcIP[j];//source ip address
	}

	switch(protocal)
	{
   
	case IP_ICMP:
		switch(type)
		{
		case ICMP_PING:

			//目标IP地址
			for(j=0; j<4; j++)
			{
				PacketTx[i++] = temp[j];
			}
		
			//类型 8位 ICMP type 0x08:请求 0x00:回复
			PacketTx[i++] = type;  

			//code 8位
			PacketTx[i++] = 0x00;//ICMP code

			//ICMP校验位和 16位
			nIcmpcheckpos = i;				
			PacketTx[i++] = 0x00;//icmp checksum set 0
			PacketTx[i++] = 0x00;//icmp checksum set 0

			//ICMP id 16位 ping进程的进程号
			PacketTx[i++] = 0x00;
			PacketTx[i++] = 0x01;

			//每个发送出去的分组递增序列号
			PacketTx[i++] = ICMP_header.sequence & 0x00ff;	//sequence number lsb
			PacketTx[i++] = ICMP_header.sequence >> 8;		//sequence number msb
			ICMP_header.sequence++;

			//数据部分
			k = temp[4]*256+temp[5];
			for (j=0; j>8) & 0x00ff);

	PacketTx[i] = 0x7e;
	TxLen = i+1;
	PktID++;
	bReject = FALSE;
}

int CPacket::CharacterEncode(int iLen)
{
	BYTE temp,endtemp;
	int i,j;

	for(i=1;i=0x00 && PacketTx[i]<0x20)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=PacketTx[i]+0x20;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
		else if(PacketTx[i]==0x7d)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=0x5d;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
		else if(PacketTx[i]==0x7e)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=0x5e;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
	}
	return(iLen);
}

int CPacket::TransferEncode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt)
{
    unsigned char *pIn, *pOut;
    int i, nTmpLen;
    
    pIn = pInPkt;
    pOut = pOutPkt;
    nTmpLen = nInLen;
	int nOutLen = 0;
    
    for(i = 0; i < nInLen; i++)
    {
        if(*pIn == PPP_FRAME_FLAG || *pIn == PPP_FRAME_ESC || *pIn < 0x20)
        {
            *pOut = PPP_FRAME_ESC;
            pOut++;
            nTmpLen++;    
            *pOut = *pIn ^ PPP_FRAME_ENC;
        }
        else
        {
            *pOut = *pIn;    
        }
        
        pIn++;
        pOut++;
    }
    nOutLen = nTmpLen;
    
    return nOutLen;    
}

int CPacket::TransferDecode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt)
{
    unsigned char *pIn, *pOut;
    int i, nTmpLen;
    
    pIn = pInPkt;
    pOut = pOutPkt;
    nTmpLen = nInLen;
	int nOutLen = 0;
     
   	for(i = 0; i < nInLen; i++)
    {
        if(*pIn == PPP_FRAME_ESC)
        {
            pIn++;
           	nTmpLen--;
            *pOut = *pIn ^ PPP_FRAME_ENC;
            
            i++;
        }    
        else
        {
            *pOut = *pIn;    
        }
        
        pIn++;
        pOut++;
    }
    nOutLen = nTmpLen;
    
    return nOutLen;
}

void CPacket::WriteLog(CString temp)
{
	CStdioFile file;
	CString filename;
	CTime time;
	time = CTime::GetCurrentTime();
	filename = time.Format("%Y%m%d");
	file.Open(filename+".log",CFile::modeNoTruncate|CFile::modeCreate|CFile::modeWrite|CFile::typeText);
	file.SeekToEnd();
	temp = time.Format("%Y.%m.%d %H:%M:%S  ")+temp+"\r\n";
	file.Write(temp,temp.GetLength());
	file.Close();
}

你可能感兴趣的:(MFC,tcp/ip,udp,网络)