免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2190 | 回复: 5
打印 上一主题 下一主题

问个raw socket使用的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-26 21:43 |只看该作者 |倒序浏览
我想学着用raw socket写一个ping,有几个问题想问问:
创建socket的时候用的是socket(AF_INET,SOCK_RAW,IPPROTO_ICMP),协议指定的是ICMP,那么构造数据包的时候还需要自己构造ip头吗?
我自己试着写了一段代码,如下。在recfrom的地方总是从socket读不出东西,一直在死等。请帮我看看是怎么回事阿!另外哪里有比较详细的raw socket的文档呢?谢谢!
#include "errexit.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <linux/icmp.h>
#include <linux/ip.h>
#include <unistd.h>

#define BUFFLENGTH    4096

void Usage()__attribute__((noreturn));
unsigned short in_cksum(unsigned short *addr, int len);

char *ProgName = "rping";
char *myip = "192.168.1.3";


int main( int argc, char * argv[])
{
    if( argc != 2 )
        Usage();
   
    struct sockaddr_in to, from;
    char *buffer[BUFFLENGTH];
    char *recvbuffer[BUFFLENGTH];
    struct icmphdr *icmphd;
    struct iphdr *iphd;
    int res;
    int tosock;
    int fromlen = sizeof(struct sockaddr);
    int one = 1;
    int *ptr_one = &one;
   
    to.sin_family = AF_INET;
    res = inet_aton(argv[1],&to.sin_addr);
    if( res < 0 )
        errexit("invalid address!\n%s\n",strerror(errno));

    memset(buffer,0x00,BUFFLENGTH);
    memset(recvbuffer,0x00,BUFFLENGTH);
   
    /*
     * create a socket to send out the icmp echo message
     */

    tosock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
    if(tosock<0)
        errexit("create socket failed!\n%s\n",strerror(errno));
   
     setsockopt(tosock, IPPROTO_IP, IP_HDRINCL,ptr_one, sizeof(one));
    /*
     * construct the ip header
     */

    iphd = ( struct iphdr *)buffer;
    iphd->version = 4;
    iphd->ihl = 5;
    iphd->tos = 0;
    iphd->id = getpid() & 0xffff;
    iphd->frag_off =0;
    iphd->ttl = 128;
    iphd->protocol =IPPROTO_ICMP;
    iphd->check = 0;
    iphd->saddr = inet_addr(myip);
    iphd->daddr = to.sin_addr.s_addr;
   
   
    /*
     * construct the icmp header
     */

    icmphd = (struct icmphdr *)(iphd+1);
    icmphd->type = ICMP_ECHO;
    icmphd->code = 10;
    icmphd->checksum = in_cksum((unsigned short *)icmphd,64);
    icmphd->un.echo.id = (short)(getpid()&0xffff);
    icmphd->un.echo.sequence = 1;

    while(1)
    {
        res = sendto(tosock,(void *)iphd,128,0,(struct sockaddr*)&to,sizeof(struct sockaddr));
        if(res == -1)
            errexit("rping error occured!\n%s\n",strerror(errno));
        else if(res == 128)
            break;
        else if (errno == EINTR)
            continue;
    }
   
    printf("done,%d bytes sent.\n",res);
   
    //while(1)

    //{

        res = recvfrom(tosock,recvbuffer,BUFFLENGTH,0,(struct sockaddr*)&from,(socklen_t *)&fromlen);
        if(res == -1)
            errexit("rping recv failed!\n%s\n",strerror(errno));
    //    else if( errno == EINTR)

    //        continue;

    //    else

    //        break;

    //}

        
    iphd = (struct iphdr *)recvbuffer;
   
    icmphd = (struct icmphdr*)(iphd+1);
    if(icmphd->type == ICMP_ECHOREPLY)
    {
        printf("ping %d bytes received,seq = %d,code = %d\n",
                res,
                icmphd->un.echo.sequence & 0xffff,
                icmphd->code & 0xff);
        
    }
   
    return 0;
}

void Usage()
{
    printf("%s dstIPaddress\n",ProgName);
    exit(-1);
}

unsigned short in_cksum(unsigned short *addr, int len)
{
    int nleft = len;
    unsigned short *w = addr;
    unsigned short answer;
    int sum = 0;
  
   
    while(nleft > 1)
    {
        sum+=*w++;
        nleft -= 2;
    }  
    if(nleft == 1)
    {
        unsigned short u = 0;
        
        *(unsigned short *)(&u) = *(unsigned short *)w;
        sum +=u;
    }
    sum = ( sum >> 16 ) + (sum & 0xffff);
    sum +=(sum>>16);                           
    answer = ~sum;                              
    return ( answer );
   
}



论坛徽章:
0
2 [报告]
发表于 2008-08-26 22:05 |只看该作者
要,RAW就是要自己构造IP头

论坛徽章:
0
3 [报告]
发表于 2008-08-26 22:35 |只看该作者
如果不设置IP_HDRINCL的话,是不是就不用自己构造ip头了

论坛徽章:
0
4 [报告]
发表于 2008-08-27 13:42 |只看该作者
我把代码改了一下,现在可以ping通自己了,但是在ping别的主机是,在recfrom的地方还是一直在死等。请帮我看看是怎么回事阿!另外哪里有比较详细的raw socket的文档呢?谢谢!
#define BUFFLENGTH    4096

void Usage()__attribute__((noreturn));
unsigned short in_cksum(unsigned short *addr, int len);

char *ProgName = "rping";
char *myip = "192.168.1.3";


int main( int argc, char * argv[])
{
    if( argc != 2 )
        Usage();
   
    struct sockaddr_in to, from;
    char *buffer[BUFFLENGTH];
    char *recvbuffer[BUFFLENGTH];
    struct icmphdr *icmphd;
    struct iphdr *iphd;
    int res;
    int tosock;
    int fromlen = sizeof(struct sockaddr);
    int one = 1;
    int *ptr_one = &one;
   
    to.sin_family = AF_INET;
    res = inet_aton(argv[1],&to.sin_addr);
    if( res < 0 )
        errexit("invalid address!\n%s\n",strerror(errno));
   
    memset(buffer,0x00,BUFFLENGTH);
    memset(recvbuffer,0x00,BUFFLENGTH);
   
    /*
     * create a socket to send out the icmp echo message
     */

    tosock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
    if(tosock<0)
        errexit("create socket failed!\n%s\n",strerror(errno));
   
    res = setsockopt(tosock, IPPROTO_IP, IP_HDRINCL,ptr_one, sizeof(one));
    if(res < 0)
        errexit("setsockopt failed!\n%s\n",strerror(errno));
    /*
     * construct the ip header
     */

    iphd = ( struct iphdr *)buffer;
    iphd->version = 4;
    iphd->ihl = 5;
    iphd->tos = 0;
    iphd->tot_len = 84;
    iphd->id = getpid() & 0xffff;
    iphd->frag_off =0;
    iphd->ttl = 32;
    iphd->protocol =IPPROTO_ICMP;
    iphd->check = 0;
    iphd->saddr = inet_addr(myip);
    iphd->daddr = to.sin_addr.s_addr;
        
    /*
     * construct the icmp header
     */

    icmphd = (struct icmphdr *)(iphd+1);
    icmphd->type = ICMP_ECHO;
    icmphd->code = 5;
    icmphd->checksum = in_cksum((unsigned short *)icmphd,64);
    icmphd->un.echo.id = (short)(getpid()&0xffff);
    icmphd->un.echo.sequence = 1;

    while(1)
    {
        res = sendto(tosock,(void *)buffer,84,0,(struct sockaddr*)&to,sizeof(struct sockaddr));
        if(res == -1)
            errexit("rping error occured!\n%s\n",strerror(errno));
        else if(res == 84)
            break;
        else if (errno == EINTR)
            continue;
    }
   
    printf("done,%d bytes sent.\n",res);
   
    char *addr = (char *)&(iphd->saddr);        
    printf("src ip address is :%d.%d.%d.%d\n",
                    addr[0]&0xff,addr[1]&0xff,addr[2]&0xff,addr[3]&0xff);
   
    while(1)
    {
        res = recvfrom(tosock,recvbuffer,BUFFLENGTH,0,(struct sockaddr*)&from,(socklen_t *)&fromlen);
        if(res == -1)
            errexit("rping recv failed!\n%s\n",strerror(errno));
        else if( errno == EINTR)
            continue;
        
        iphd = (struct iphdr *)recvbuffer;
   
        char *saddr = (char *)&(iphd->saddr);
        
        icmphd = (struct icmphdr*)(iphd+1);
        if(icmphd->type == ICMP_ECHO)
            continue;
        if(icmphd->type == ICMP_ECHOREPLY)
        {
            printf("ping %d bytes received,seq = %d,code = %d\n",
                    res,
                    icmphd->un.echo.sequence & 0xffff,
                    icmphd->code & 0xff);
            printf("src ip address is :%d.%d.%d.%d\n",
                    saddr[0]&0xff,saddr[1]&0xff,saddr[2]&0xff,saddr[3]&0xff);
            break;
        
        }
    }
    return 0;
}


[ 本帖最后由 zhoufanking 于 2008-8-27 23:19 编辑 ]

论坛徽章:
0
5 [报告]
发表于 2008-08-27 23:40 |只看该作者
上google搜一下ping的源代码看看,比较一下

论坛徽章:
0
6 [报告]
发表于 2008-08-27 23:57 |只看该作者
我用TCPDUMP看了一下,对方收到了我发送的echo request但没有发出echo reply.这是怎么回事呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP