zoukankan      html  css  js  c++  java
  • 记一次蛋疼的Raw socket发送经历。附:Raw socket编程总结

    最近在做信息安全导论的实验,实验很简单,就是实现一个ping程序,能够扫描主机是否打开的情况,但是,我也就纳了闷了,每次有个不易发现的bug(可能由于自己知识有限造成的),都得让我碰上,并且还得为这个bug操心好长时间,才能解决。。。。。。(抱怨是最浪费时间的一种行为!)ok~为了下次不再犯同样的错误,现在先记录一下吧~

    我的错误是,在一切都准备好了的时候(初始化套接字,创建套接字,填充icmp数据头,设定超时时间)发送数据包,成功,但是一旦接受就会超时,为此,我找了个能发送成功的程序,一步步的对照着看看哪儿不一样,但是对照完了,发现一些核心代码是一样的。。。。。。这就蛋疼了,然后我就怀疑是不是因为这些小的错误导致的呢?我一步步的改正,首先我怀疑我的可能是因为发送和接受我放在了不同的函数里面,导致,在一个函数返回的时间里,接受函数错过了接受(现在想想真是有病乱投医啊。。。。。。。操作系统在端口应该有缓存的吧,在接受到数据后,会存到缓存里,然后才会调用。。。。。)我就把所有函合并成了一个函数,果不其然,没有任何效果,依旧是发送超时。在经历无尽的折磨以后,我发现我的变量全是定义在类里面的,而其他的程序就是在函数里面直接声明,或者就是全局变量的,难道是因为类,半信半疑我就把所有定义在类里面的变量放到了cpp文件当中,作为全局变量调用,成功了~我去了!不应该啊,这是因为啥???在一个函数调用类里面的变量后,不改变内存中值?上课时不是这么讲的啊。。。。。。苦逼的程序猿我,又一次发挥了初中时在物理课上学的控制变量法。。。。。。。。(我真丫该去学物理去。。。。。)一个一个的把变量弄回去,好了,终于发现了!!!!!!发送的数据包(实质是一个数组)没有初始化,我擦了,为毛没有初始化会出现这个情况?我发送时就是发送了icmp的头部数据,跟其他数据没有关系啊,在经过我控制变量法的不断检验下,不管缓冲区有多大,只有初始化为0,后才可能接受成功,也就是被ping的主机识别。具体原因还有待进一步的研究。

    下面来对原始套接字编程进行说明一下:

    总体步骤是:

    1、用管理员权限打开编辑器(vc6.0或vs)

    2、创建ip和icmp的头部数据结构

    ip头部数据结构:

    typedef struct _iphdr //定义IP固定首部
    { 
        unsigned char h_lenver; //4位首部长度+4位IP版本号
        unsigned char tos; //8位服务类型TOS 
        unsigned short total_len; //16位总长度(字节)
        unsigned short ident; //16位标识
        unsigned short frag_and_flags; //3位标志位
        unsigned char ttl; //8位生存时间 TTL 
        unsigned char proto; //8位协议 (TCP, UDP 或其他) 
        unsigned short checksum;//16位IP首部校验和
        unsigned int sourceIP; //32位源IP地址
        unsigned int destIP; //32位目的IP地址
    }IpHeader;

    icmp头部数据结构:

    typedef struct _icmphdr
    {
     unsigned char i_type;     //类型
     unsigned char i_code;     //代码
     unsigned short i_cksum;  //检验和
     unsigned short i_id;        //标识符
     unsigned short i_seq;     //序列号
     unsigned long i_timestamp;  //当前时间  =(unsigned long)::GetTickCount();
    }IcmpHeader; 

    3、初始化原始套接字

    WORD wVersionRequested = MAKEWORD(2, 2);  
    WSADATA wsaData;  
    if(WSAStartup(wVersionRequested, &wsaData) != 0)  
    {  
       int flag = ::WSAGetLastError();

        CString str;
        str.Format(_T("%d"), flag);

        MessageBox(_T("套接字初始化失败!")+str);

      }

    4、声明套接字

    sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

    5、设置套接字选项(这里是不需要自己设置ip的简单icmp程序)

    int nTime = 1000;      
    int ret = ::setsockopt(sRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTime, sizeof(nTime)); 

    6、设置发送和接受的函数选项

    SOCKADDR_IN dest;
    dest.sin_family = AF_INET; dest.sin_port = htons(0); dest.sin_addr.S_un.S_addr = inet_addr(pBuf); /*设置要ping的主机ip(pBuf)*/

    SOCKADDR_IN from;
    int nLen = sizeof(from);

    6、发送并接受信息

    for (int i = 0; i < 4; i++)
        {
            icmp->i_cksum = 0;
            icmp->i_seq = i;
            icmp->i_timestamp = ::GetTickCount();
            icmp->i_id = ::GetCurrentProcessId();
            icmp->i_cksum = cheNum((USHORT*)buff, sizeof(IcmpHeader));
    
            nRet = ::sendto(sRaw, buff, sizeof(IcmpHeader), 0, (SOCKADDR *)&dest, sizeof(dest));
    
            if(nRet == SOCKET_ERROR)  
            {
                int flag = ::WSAGetLastError();
                CString str;
                str.Format(_T("%d"), flag);
                MessageBox(_T(" sendto() failed: ")+str);   
            }
    
            nRet = ::recvfrom(sRaw, recvBuff, 1024 , 0, (SOCKADDR *)&from, &nLen);  
            if(nRet == SOCKET_ERROR)  
            {  
                if(::WSAGetLastError() == WSAETIMEDOUT)  
                {  
                    MessageBox(_T(" timed out/n"));  
                }  
            }
    int nTick = ::GetTickCount(); IcmpHeader* pRecvIcmp = (IcmpHeader*)(recvBuff + 20);
    if(pRecvIcmp->i_type != 0) { CString str; str.Format(_T("%d"),pRecvIcmp->i_type); MessageBox(_T(" nonecho type"), str+_T("recvd")); } else if(pRecvIcmp->i_id != ::GetCurrentProcessId()) { MessageBox(_T(" someone else's packet!")); } else { m_state = _T("open");/*返回到edit控件中*/ UpdateData(false); } }

    7、关闭并清理

    closesocket(sRaw);      
    WSACleanup();
  • 相关阅读:
    Android-调用优酷SDK上传视频
    新浪微博客户端(16)-获得并显示用户昵称
    新浪微博客户端(15)-保存用户名和密码
    转:Java NIO系列教程(九) Pipe
    新浪微博客户端(14)-截取回调地址中的授权成功的请求标记,换取access_token
    iOS-AFN "Request failed: unacceptable content-type: text/plain"
    新浪微博客户端(13)-使用UIWebView加载OAuth授权界面
    iOS-(kCFStreamErrorDomainSSL, -9802)
    转:Java NIO系列教程(八) DatagramChannel
    转:Java NIO系列教程(七) Socket Channel
  • 原文地址:https://www.cnblogs.com/MyselfDancing/p/3478431.html
Copyright © 2011-2022 走看看