计算UDP校验和遇到的弱智问题。不知道对初学者有没有用。

以下是计算UDP校验和以及发送原始数据的源代码

#include <Winsock2.h>
#include <stdio.h>

#define IP_HDRINCL                 2 // Header is included with data.

typedef struct _IPHEADER
{
    UCHAR    VerHeadLen;                    //版本号和头长度
    UCHAR    TOS;                        //服务类型
    USHORT    Length;                //IP包总长度
    USHORT    ID;                            //IP包唯一标识
    USHORT    Flags;                        //标志
    UCHAR    TTL;                        //生存时间
    UCHAR    Protocol;                    //协议
    USHORT    Checksum;                    //校验和
    ULONG    SourceIP;                    //源IP地址
    ULONG    DestIP;                        //目标IP
}IPHEADER;

typedef struct _UDPHEADER
{
    USHORT    SourcePort;                    //源端口
    USHORT    DestPort;                    //目的端口
    USHORT    Length;                //包长度
    USHORT    CheckSum;                    //校验和
}UDPHEADER;

USHORT checksum(USHORT * buff, int size)
{
    ULONG cksum = 0;
    while (size > 1)
    {
        cksum += *(buff++);
        size -= sizeof(USHORT);
    }
    if(size)
    {
        cksum += *((UCHAR*)buff);
    }

    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);
    return (USHORT)(~cksum);
}

void UdpHeaderChecksum(IPHEADER *IpHeader,UDPHEADER *UdpHeader,char * payload,int payloadlen)
{
    char buf[1024];
    char *ptr = buf;
    int chksumlen = 0;
    ULONG zero = 0;
   
    //包含源IP地址和目的IP地址
    memcpy(ptr,&IpHeader->SourceIP,sizeof(IpHeader->SourceIP));
    ptr += sizeof(IpHeader->SourceIP);
    chksumlen += sizeof(IpHeader->SourceIP);
    memcpy(ptr,&IpHeader->DestIP,sizeof(IpHeader->DestIP));
    ptr += sizeof(IpHeader->DestIP);
    chksumlen += sizeof(IpHeader->DestIP);

    //8位0域
    memcpy(ptr,&zero,1);
    ptr += 1;
    chksumlen += 1;
    //协议
    memcpy(ptr,&IpHeader->Protocol,sizeof(IpHeader->Protocol));
    ptr += sizeof(IpHeader->Protocol);
    chksumlen += sizeof(IpHeader->Protocol);
    //UDP长度
    memcpy(ptr,&UdpHeader->Length,sizeof(UdpHeader->Length));
    ptr += sizeof(UdpHeader->Length);
    chksumlen += sizeof(UdpHeader->Length);
    //UDP端口号
    memcpy(ptr,&UdpHeader->SourcePort,sizeof(UdpHeader->SourcePort));
    ptr += sizeof(UdpHeader->SourcePort);
    chksumlen += sizeof(UdpHeader->SourcePort);
    memcpy(ptr,&UdpHeader->DestPort,sizeof(UdpHeader->DestPort));
    ptr += sizeof(UdpHeader->DestPort);
    chksumlen += sizeof(UdpHeader->DestPort);
    //UDP长度
    memcpy(ptr,&UdpHeader->Length,sizeof(UdpHeader->Length));
    ptr += sizeof(UdpHeader->Length);
    chksumlen += sizeof(UdpHeader->Length);
    //16位UDP校验和
    memcpy(ptr,&zero,sizeof(UdpHeader->CheckSum));
    ptr += sizeof(USHORT);
    chksumlen += sizeof(USHORT);
    //净荷
    memcpy(ptr,payload,payloadlen);
    ptr += payloadlen;
    chksumlen += payloadlen;
    //补齐到下一个16位边界
    for(int i = 0; i < payloadlen %2; i++)
    {
        *ptr = 0;
        ptr++;
        chksumlen++;
    }
    //计算校验和,填充到UDP头
    UdpHeader->CheckSum = checksum((USHORT*)buf,chksumlen);
}

int main()
{
    int i = 0;
    WSADATA wsaData;
    int wsaret = WSAStartup(0x101,&wsaData);
    if(wsaret != 0)
    {
        printf("WSAStartup失败/n");
    }
    char szDestIP[] = "192.168.12.110";
    char szSourceIP[] = "192.168.12.169";
    USHORT nDestPort = 1234;
    USHORT nSourcePort = 8888;
    char szMsg[] = "123456";
    int nMsgLen = strlen(szMsg);
    //创建原始套接字
    SOCKET sRaw = ::socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
    //有效IP头包含选项
    BOOL bIncl = TRUE;
    i = ::setsockopt(sRaw,IPPROTO_IP,IP_HDRINCL,(char*)&bIncl,sizeof(bIncl));
    char buff[1024] = {0};

    int TotalLength = sizeof(IPHEADER) + sizeof(UDPHEADER) + nMsgLen;
    //IP头
    IPHEADER * IpHeader = (IPHEADER*)buff;
    IpHeader->VerHeadLen = (4 << 4 | (sizeof(_IPHEADER)/sizeof(ULONG)));
    IpHeader->Length = TotalLength;
    IpHeader->TTL = 128;
    IpHeader->Protocol = IPPROTO_UDP;
    IpHeader->SourceIP = ::inet_addr(szSourceIP);
    IpHeader->DestIP = ::inet_addr(szDestIP);
    IpHeader->Checksum = checksum((USHORT*)IpHeader,sizeof(IPHEADER));
    //UDP头
    UDPHEADER * UdpHeader = (UDPHEADER*)(buff + sizeof(IPHEADER));
    UdpHeader->SourcePort = htons(nSourcePort);
    UdpHeader->DestPort = htons(nDestPort);
    UdpHeader->Length = htons(sizeof(UDPHEADER) + nMsgLen);
    UdpHeader->CheckSum = 0;
    UdpHeaderChecksum(IpHeader,UdpHeader,szMsg,nMsgLen);
    char* pData = buff + sizeof(IPHEADER) + sizeof(UDPHEADER);
    memcpy(pData,szMsg,nMsgLen);
   
    //设置目的地址
    SOCKADDR_IN Addr = {0};
    Addr.sin_family = AF_INET;
    Addr.sin_port = htons(nDestPort);
    memset(Addr.sin_zero,0,8);
    Addr.sin_addr.S_un.S_addr = ::inet_addr(szDestIP);
   
    //发送原始UDP封包
    int nRet = 0;
    for(i = 0; i < 5; i++)
    {
        nRet = sendto(sRaw,buff,TotalLength,0,(sockaddr*)&Addr,sizeof(sockaddr));
        if(nRet == SOCKET_ERROR)
        {
            printf("sendto() faild:%d/n",WSAGetLastError());
            break;
        }
        else
        {
            printf("send %d bytes/n",nRet);
        }
    }
    closesocket(sRaw);
    return 0;
}


刚开始时,服务程序根本接收不到我发的包,用ethereal抓包时发现数据确实是发送出去了,但显示信息表示UDP校验和不正确。 后来发现计算UDP校验和时,我把IP头也计算进去,实际上,UDP的校验和只需要计算从UDP头开始到后面的净荷。
找到问题后觉得十分简单,但如果有些朋友也犯了和我一样的错误的话,希望有所帮助。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值