应用层:
功能:用户接口,文件传输、电子邮件、虚拟终端、文件服务
设备:网关
协议:HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet
表示层:
功能:数据的表示,压缩和加密
设备:网关
协议:无
会话层:
功能:会话的建立和结束
设备:网关
协议:无
传输层:
功能:提供端对端的接口
设备:网关
协议:TCP UDP
网络层:
功能:为数据报选择路由,寻址
设备:路由器
协议:IP、ICMP、IGMP、RIP
数据链路层:
功能:传输有地址的帧与错误校验功能
设备:交换机、网桥、网卡
协议:PPP、ARP、MTU、RARP、SLIP、CSLIP
物理层:
功能:传输比特流,以二进制数据形式在物理媒体上传输数据
设备:集线器、中继器
协议:IEEE802、IEEE802.2、ISO2110
图片来源: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
应用层:
功能:用户接口,文件传输、电子邮件、虚拟终端、文件服务
设备:网关
协议:HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet
传输层:
功能:提供端对端的接口
设备:网关
协议:TCP UDP
网络层:
功能:为数据报选择路由,寻址
设备:路由器
协议:IP、ICMP、IGMP、RIP
数据链路层:
功能:传输有地址的帧与错误校验功能
设备:交换机、网桥、网卡
协议:PPP、ARP、MTU、RARP、SLIP、CSLIP
十六进制加法计算器:
https://www.9321.cn/digital-computation/hex-addition-calculator.php
crc校验:http://www.ip33.com/crc.html
UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。伪首部+UDP首部+数据一起计算校验和。
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字节的固定部分)
ping使用的是 ICMP 的请求回显/回显应答类型的报文,它的内容包括标识符、序列号以及回显数据3部分,报文大小默认为 64 字节(header的8字节+body的56字节)。
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 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