一、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
1.2 数据封装过程:
图片来源: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报文格式
2.1.2 IP报文解析及校验和计算:
十六进制加法计算器:
https://www.9321.cn/digital-computation/hex-addition-calculator.php
crc校验:http://www.ip33.com/crc.html
2.2 UDP报文
2.1.1 UDP报文格式:
2.1.2 UDP报文解析及校验和计算:
UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。伪首部+UDP首部+数据一起计算校验和。
2.3 TCP报文
2.3.1 TCP报文格式
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字节的固定部分)
2.3.2 TCP三次握手和四次挥手过程
2.4 ICMP报文
2.4.1 ICMP报文格式
ping使用的是 ICMP 的请求回显/回显应答类型的报文,它的内容包括标识符、序列号以及回显数据3部分,报文大小默认为 64 字节(header的8字节+body的56字节)。
2.4.2 ICMP报文解析及校验和计算
ICMP校验和:
生成:先将校验和置为0,然后将ICMP报文的header+body按16bit分组求和。如果结果溢出,则将高16位和低16位求和,直到高16位为0。最后求反就是检验和的值。
三、相关代码分享:
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<string> 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<mm; k++)
{
temp[k] = m_senddata[l++];
}
int nPingNum = 10;
string sPingNum;
if(GetInitFileStrings(strPath, _T("PPP"), _T("PingNum"), sPingNum))
{
nPingNum = atoi(sPingNum.c_str());
ffprint("GetInitFileStrings nPingNum:%d", nPingNum);
}
for(int i = 0 ; i < nPingNum; i++)
{
::WaitForSingleObject(m_hStopEvent, 100);
m_PPPPacket.IP_header.protocol = IP_ICMP;
m_PPPPacket.CreateIpPkt(IP_ICMP, ICMP_PING, temp);
if(m_PPPPacket.TxLen > 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<j+4; k++)
{
temp[k] = DataHex[l++];
}
m_PPPPacket.IP_header.protocol = IP_UDP;
m_PPPPacket.CreateIpPkt(IP_UDP, NULL, temp);
if(m_PPPPacket.TxLen > 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 <windows.h>
#include "crc.h"
#include <afxext.h>
#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<length; i++)
{
rslt += (unsigned long)(hex[i])<<(8*(length-1-i));
}
return rslt;
}
CString Ascii2Hex(CString strASCII)
{
int i;
int length = strASCII.GetLength();
CString strHEX;
CString temp;
for (i = 0; i < length; i++)
{
temp.Format("%2hhX ", strASCII.GetAt(i));// %2hhX 解决出现的FFFFFF问题
strHEX = strHEX + temp;
}
return strHEX;
}
//字符转换为16进制数据
char Char2Hex(char ch)
{
if ((ch >= '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<option[j].bLength-2; i++)
{
option[j].bData[i]=pOption[i+wStart];
}
option[j].bData[i]='\0';
wStart = i + wStart;
j++;
}
nOptionNum = j;
switch(wProtocolType)
{
case PROTOCOL_LCP:
{
for(i=0; i<j; i++)
{
if (option[i].bType > 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; i<j; i++)
{
if ((option[i].bType>0 && 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<option[i].bLength-2;k++)
{
SrcIP[k] = option[i].bData[k];
ffprint("SrcIP[%d]:%02x", k, SrcIP[k]);
}
}
break;
default:
option[i].bReject = TRUE;
bReject = TRUE;
break;
}
}
}
break;
}
}
uint16_t crc16_x25(uint8_t *data, int length){
uint8_t i;
uint16_t crc = 0xffff; // Initial value
while(length--)
{
crc ^= *data++; // crc ^= *data; data++;
for (i = 0; i < 8; ++i)
{
if (crc & 1)
crc = (crc >> 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<nOptionNum; k++)
{
if(!option[k].bReject)
{
PacketTx[i++] = option[k].bType;
PacketTx[i++] = option[k].bLength;
for(j=0; j<option[k].bLength-2; j++)
PacketTx[i++] = option[k].bData[j];
}
}
}
CurState = PPP_STATE_LCP_PERIOD;
break;
case PPP_CODE_ACK:
{
for(i=1; i<5; i++)
{
PacketTx[i] = pPkt[i]; //frame head and protocol
}
PacketTx[i++] = CodeVal; //code
int idIndex = i++;
PacketTx[idIndex] = pPkt[idIndex]; //回复包的ID与请求包的ID一致
nLenthPos = i; //get the length postion
i+=2;
while(pPkt[i] != 0x7e) //数据域直接拷贝
{
PacketTx[i] = pPkt[i];
i++;
}
i-=2;
PacketTx[i]='\0';
PacketTx[i+1]='\0';
CurState = PPP_STATE_LCP_PASS;
break;
}
case PPP_CODE_REJ:
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;
for(k=0; k<nOptionNum; k++) //LCP配置项 添加拒绝的配置项
{
if(option[k].bReject)
{
PacketTx[i++] = option[k].bType;
PacketTx[i++] = option[k].bLength;
for(j=0; j<option[k].bLength-2; j++)
PacketTx[i++]=option[k].bData[j];
}
}
CurState = PPP_STATE_LCP_PERIOD;
break;
case PPP_CODE_TERM_LINK:
{
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;
while(pPkt[i] != 0x7e) //数据域直接拷贝
{
PacketTx[i] = pPkt[i];
i++;
}
i-=2;
PacketTx[i]='\0';
PacketTx[i+1]='\0';
CurState = PPP_STATE_TERM_LINK;
break;
}
}
break;
case PROTOCOL_IPCP:
switch(CodeVal)
{
case PPP_CODE_REQ:
{
for(i=1;i<5;i++)
{
PacketTx[i] = pPkt[i]; //frame head and protocol
}
PacketTx[i++] = 0x01; //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] = 0x00;
PacketTx[i+1] = 0x00;
}
else
{
if(CurState == PPP_STATE_NCP_NAK)
{
PacketTx[i++] = 0x03;
PacketTx[i++] = 0x06;
ffprint("IPCP PPP_CODE_REQ nOptionNum:%d", nOptionNum);
for(k=0; k<nOptionNum; k++)
{
if(!option[k].bReject)
{
for(j=0;j<option[k].bLength-2;j++)
{
//ffprint("NAK SrcIP[%d]:%02x", j, SrcIP[j]);
PacketTx[i++] = SrcIP[j];
}
}
}
}
}
break;
}
case PPP_CODE_ACK:
{
for(i=1;i<5;i++)
{
PacketTx[i] = pPkt[i]; //frame head and protocol
}
PacketTx[i++] = 0x02; //code
int idIndex = i++;
PacketTx[idIndex] = pPkt[idIndex]; //回复包的ID与请求包的ID一致
nLenthPos = i; //get the length postion
i+=2;
while(pPkt[i] != 0x7e) //数据域直接拷贝
{
PacketTx[i] = pPkt[i];
i++;
}
i-=2;
PacketTx[i]=0x00;
PacketTx[i+1]=0x00;
break;
}
case PPP_CODE_NAK:
break;
case PPP_CODE_REJ:
break;
default:
break;
}
break;
default:
break;
}
wLen = i-5;
if(wProType == PROTOCOL_LCP)
{
PacketTx[nLenthPos++] = wLen/256;
PacketTx[nLenthPos] = wLen%256;
}
else
{
char Hight[2];
char Low[2];
DectoHex((int)(wLen/256), Hight, 1);
DectoHex((int)(wLen%256), Low, 1);
PacketTx[nLenthPos++] = (BYTE)Hight[0];
PacketTx[nLenthPos++] = (BYTE)Low[0];
ffprint("wLen:%d Hight:%02x, Low:%02x", wLen, Hight[0], Low[0]);
}
//CRC校验
//CString strText;
//strText.Format(_T("校验:%s"), HexToString(PacketTx+1, i-1));
//ffprint("strText:%s", strText);
wChecksum = m_crc.CountCRC(PacketTx+1, i-1);//get checksum and copy to szPacketTx[crcpos]
//wChecksum=m_crc.CountCRC(TestByte, 14);
//2.
PacketTx[i++]=(wChecksum & 0x00ff);
PacketTx[i++]=((wChecksum>>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<k; j++)
{
PacketTx[i++] = temp[6+j];
}
break;
default:
break;
}
//ICMP 校验和计算
wlow = 0;
whigh = 0;
for(j=nIcmpcheckpos-2; j<i; j+=2)
{
whigh += PacketTx[j];
}
for(j=nIcmpcheckpos-1; j<i; j+=2)
{
wlow += PacketTx[j];
}
//write the sub header checksum
wlow += whigh/256;
whigh = (whigh & 255)+wlow/256;
wlow = (wlow & 255)+whigh/256;
whigh = ~whigh;
wlow = ~wlow;
PacketTx[nIcmpcheckpos++] = (whigh & 0x00ff);
PacketTx[nIcmpcheckpos] = (wlow & 0x00ff);
break;
case IP_UDP:
//目标IP + 源端口 + 目标端口 + 长度
for(j=0; j<10; j++)
{
PacketTx[i++] = temp[j];
}
//UDP校验和
nIcmpcheckpos = i;
PacketTx[i++] = 0x00;
PacketTx[i++] = 0x00;
//UDP 发送的数据
k = temp[8]*256+temp[9]+4;
for(j=12;j<k;j++)
{
PacketTx[i++]=temp[j];
}
//计算UDP校验和
wlow = 0x0000;
whigh = 0x0000;
for(j=nIcmpcheckpos-14; j<i; j+=2)
{
whigh += PacketTx[j];
}
for(j=nIcmpcheckpos-13; j<i; j+=2)
{
wlow += PacketTx[j];
}
whigh += temp[8];
wlow += 0x11;
wlow += temp[9];
//write the sub header checksum
wlow += whigh/256;
whigh = (whigh & 255)+wlow/256;
wlow = (wlow & 255)+whigh/256;
whigh = ~whigh;
wlow = ~wlow;
PacketTx[nIcmpcheckpos++] = (whigh & 0x00ff);
PacketTx[nIcmpcheckpos] = (wlow & 0x00ff);
default:
break;
}
wLen=i-5;
PacketTx[nLenthPos++]=wLen/256;
PacketTx[nLenthPos]=wLen%256;
//计算IP校验和
wlow=0;
whigh=0;
for(j=iHeadpos; j<20+iHeadpos; j+=2)
{
whigh += PacketTx[j];
}
for(j=iHeadpos+1; j<=20+iHeadpos; j+=2)
{
wlow += PacketTx[j];
}
wlow += whigh/256;
whigh = (whigh & 255)+wlow/256;
wlow = (wlow & 255)+whigh/256;
whigh = ~whigh;
wlow = ~wlow;
PacketTx[nHeadcheckpos++] = (whigh & 0x00ff);
PacketTx[nHeadcheckpos] = (wlow & 0x00ff);
//计算CRC校验
wChecksum = m_crc.CountCRC(PacketTx+1,i-1);//get checksum and copy to szPacketTx[crcpos]
PacketTx[i++] = (wChecksum & 0x00ff);
PacketTx[i++] = ((wChecksum>>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<iLen;i++)
{
if(PacketTx[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();
}