zoukankan      html  css  js  c++  java
  • 原始UDP封包发送

    发送原始UDP封包时:

    1 以IPPROTO_UDP 为协议类型创建一个原始套接字,打开原始套接字上的IP_HDRINCL选项

    2 构建UDP封包,要先设置IP头,设置UDP头,最后UDP净荷数据。

    3 初始化完整的UDP封包之后,调用sendto函数即可将他发送。

    计算UDP封包校验和的过程如下:

    void ComputeUdpPseudoHeaderChecksum(
        IPHeader    *pIphdr,
        UDPHeader *pUdphdr,
        char    *payload,
        int      payloadlen
        )
    {
        char buff[1024];
        char *ptr = buff;
        int chksumlen = 0;
        ULONG zero = 0;
        
        // 包含源IP地址和目的IP地址
        memcpy(ptr, &pIphdr->ipSource, sizeof(pIphdr->ipSource));
        ptr += sizeof(pIphdr->ipSource);
        chksumlen += sizeof(pIphdr->ipSource);
    
        memcpy(ptr, &pIphdr->ipDestination, sizeof(pIphdr->ipDestination));
        ptr += sizeof(pIphdr->ipDestination);
        chksumlen += sizeof(pIphdr->ipDestination);
    
        // 包含8位0域
        memcpy(ptr, &zero, 1);
        ptr += 1;
        chksumlen += 1;
    
        // 协议
        memcpy(ptr, &pIphdr->ipProtocol, sizeof(pIphdr->ipProtocol));
        ptr += sizeof(pIphdr->ipProtocol);
        chksumlen += sizeof(pIphdr->ipProtocol);
    
        // UDP长度
        memcpy(ptr, &pUdphdr->len, sizeof(pUdphdr->len));
        ptr += sizeof(pUdphdr->len);
        chksumlen += sizeof(pUdphdr->len);
    
        // UDP源端口号
        memcpy(ptr, &pUdphdr->sourcePort, sizeof(pUdphdr->sourcePort));
        ptr += sizeof(pUdphdr->sourcePort);
        chksumlen += sizeof(pUdphdr->sourcePort);
    
        // UDP目的端口号
        memcpy(ptr, &pUdphdr->destinationPort, sizeof(pUdphdr->destinationPort));
        ptr += sizeof(pUdphdr->destinationPort);
        chksumlen += sizeof(pUdphdr->destinationPort);
    
        // 又是UDP长度
        memcpy(ptr, &pUdphdr->len, sizeof(pUdphdr->len));
        ptr += sizeof(pUdphdr->len);
        chksumlen += sizeof(pUdphdr->len);
    
        // 16位的UDP校验和,置为0
        memcpy(ptr, &zero, sizeof(USHORT));
        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头
        pUdphdr->checksum = checksum((USHORT*)buff, chksumlen);
    }

    发送原始UDP封包的过程如下:

    int main()
    {
        // 输入参数信息
        char szDestIp[] = "10.16.115.88";      //  <<== 填写目的IP地址
        char szSourceIp[] = "127.0.0.1";      //  <<== 填写您自己的IP地址
    
        USHORT nDestPort = 4567;
        USHORT nSourcePort = 8888;
        char szMsg[] = "This is a test \r\n";
        int nMsgLen = strlen(szMsg);
    
        // 创建原始套节字
        SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
    
        // 有效IP头包含选项
        BOOL bIncl = TRUE;
        ::setsockopt(sRaw, IPPROTO_IP, IP_HDRINCL, (char *)&bIncl, sizeof(bIncl));
    
        char buff[1024] = { 0 };
    
        // IP头
        IPHeader *pIphdr = (IPHeader *)buff;
        pIphdr->iphVerLen = (4<<4 | (sizeof(IPHeader)/sizeof(ULONG)));
    
        pIphdr->ipLength = ::htons(sizeof(IPHeader) + sizeof(UDPHeader) + nMsgLen);
        pIphdr->ipTTL = 128;
        pIphdr->ipProtocol = IPPROTO_UDP;
        pIphdr->ipSource = ::inet_addr(szSourceIp);
        pIphdr->ipDestination = ::inet_addr(szDestIp);
        pIphdr->ipChecksum = checksum((USHORT*)pIphdr, sizeof(IPHeader));
    
        // UDP头
        UDPHeader *pUdphdr = (UDPHeader *)&buff[sizeof(IPHeader)];
        pUdphdr->sourcePort = htons(8888);
        pUdphdr->destinationPort = htons(nDestPort);
        pUdphdr->len = htons(sizeof(UDPHeader) + nMsgLen);
        pUdphdr->checksum = 0;
    
        char *pData = &buff[sizeof(IPHeader) + sizeof(UDPHeader)];
        memcpy(pData, szMsg, nMsgLen);
    
        ComputeUdpPseudoHeaderChecksum(pIphdr, pUdphdr, pData, nMsgLen);
    
        // 设置目的地址
        SOCKADDR_IN destAddr = { 0 };
        destAddr.sin_family = AF_INET;
        destAddr.sin_port = htons(nDestPort);
        destAddr.sin_addr.S_un.S_addr = ::inet_addr(szDestIp);
    
        // 发送原始UDP封包
        int nRet;
        for(int i=0; i<5; i++)
        {
            nRet = ::sendto(sRaw, buff, 
                sizeof(IPHeader) + sizeof(UDPHeader) + nMsgLen, 0, (sockaddr*)&destAddr, sizeof(destAddr));
            if(nRet == SOCKET_ERROR)
            {
                printf(" sendto() failed: %d \n", ::WSAGetLastError());
                break;
            }
            else
            {
                printf(" sent %d bytes \n", nRet);
            }
        }
    
        ::closesocket(sRaw);
    
        getchar();
        return 0;
    }
  • 相关阅读:
    二分法查找
    重构方法之一:提炼方法(Extract Method)读书笔记
    使用SQL命令手动写入Discuz帖子内容
    调整linux系统时间和时区
    怎样给访问量过大的mysql数据库减压
    MySQL提示“too many connections”的解决办法
    CentOS 6安装php加速软件Zend Guard
    CmsTop 大众版运行环境搭建 (CentOS+Nginx+PHP FastCGI)
    LEMP构建高性能WEB服务器(CentOS+Nginx+PHP+MySQL)
    CentOS-6.3安装配置Nginx
  • 原文地址:https://www.cnblogs.com/xing901022/p/2733038.html
Copyright © 2011-2022 走看看