zoukankan      html  css  js  c++  java
  • icmp 流量抓取 转发 代理(2)

    客户端C到服务器S的icmp包经过本机P时被截获,在上一篇中已经介绍了如何获取原始目的地址,你必须将数据转发到原始目的地址S,并且在收到从原始目的地址的响应之后转发给客户端。此时,要实现透明代理,则你返回给客户端的icmp响应的源地址必须为客户端请求的原始目的地址S。由于使用的是raw socket,无法用IP_TRANSPARENT的socket选项绑定非本机地址的方法(bind会报错:提示无法绑定这个地址),因此使用IP_HDRINCL的socket选项,手动填充IP头将源地址设为S,目的地址设为C(其实就是将原来从客户端收到的icmp包的两个地址对调)。
        socklen_t sender_len;
        struct msghdr msg;
        struct iovec iov;
        struct sockaddr_in sender_addr;
        sender_len = sizeof(sender_addr);
        char buf[2048] = {0};
        int len = 0;
        char cmsg_buf[2048] = {0};

        msg.msg_name = &sender_addr;
        msg.msg_namelen = sender_len;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_iov->iov_base = buf;
        msg.msg_iov->iov_len = 2048;
        msg.msg_control = cmsg_buf;
        msg.msg_controllen = 2048;
        msg.msg_flags = 0;

        //从客户端接收icmp包
        len = recvmsg(sockfd,&msg,0);
        if (len == -1) {
            perror("recvmsg()");
        } else if (len == 0) {
            printf("Connection Closed ");
        } else {
            printf("Read from Client: len [%d] --content:", len);
            print_data(buf,len);

            struct cmsghdr * cmsg = NULL;
            for (cmsg = CMSG_FIRSTHDR(&msg);
                cmsg != NULL;
                cmsg = CMSG_NXTHDR(&msg, cmsg))
            {
                // ignore the control headers that don't match what we want
                if (cmsg->cmsg_level != IPPROTO_IP ||
                    cmsg->cmsg_type != IP_PKTINFO)
                {
                    continue;
                }
                struct in_pktinfo *pi = CMSG_DATA(cmsg);
                // printf("ipi_spec_dst:%s ", inet_ntoa(pi->ipi_spec_dst));
                // printf("ipi_addr:%s ", inet_ntoa(pi->ipi_addr));
                char sender_ip[32] = {0};
                int sender_port = 0;
                transfer_sock_addr(&sender_addr, sender_ip, 32, &sender_port);
                printf("source ip:%s port:%d ",sender_ip,sender_port);
                // at this point, peeraddr is the source sockaddr
                // pi->ipi_spec_dst is the destination in_addr
                // pi->ipi_addr is the receiving interface in_addr
            }
            char orig_ip[32] = {0};
            int orig_port = 0;
            struct sockaddr_in *orig_addr;
            for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
                    cmsg = CMSG_NXTHDR(&msg,cmsg)) {
                if (cmsg->cmsg_level == SOL_IP
                        && cmsg->cmsg_type == IP_ORIGDSTADDR) {
                    orig_addr = (struct sockaddr_in *) CMSG_DATA(cmsg);
                    transfer_sock_addr(orig_addr, orig_ip, 32, &orig_port);
                    break;
                }
            }
            if (cmsg == NULL) {
                printf("IP_ORIGDSTADDR not enabled or small buffer or I/O error");
                return;
            }
            printf("original destination ip:%s - port:%d ", orig_ip, orig_port);


            // struct sockaddr_in  sin;
            // memset(&sin, 0, sizeof(sin));
            // sin.sin_family = AF_INET;
            // sin.sin_addr.s_addr = inet_addr("192.168.128.2");
            // sin.sin_port = htons(orig_port);


            int i;
            int iphdrlen;       //ip头长度
            struct ip *ip;
            struct icmp *icmp;
        
            ip = (struct ip *)buf;
            iphdrlen = ip->ip_hl << 2; //求IP报文头长度,即IP报头长度乘4
            icmp = (struct icmp *)(buf + iphdrlen); //越过IP头,指向ICMP报头
            len -= iphdrlen;
            //转发到服务端
            printf("sendto server ");
            sendto(sockfd, icmp, len, 0, (struct sockaddr *)&orig_addr, sizeof(struct sockaddr));
            //从服务端接收icmp响应
            printf("recvfrom server ");
            if((len = recvfrom(sockfd,buf,2048,0,
                (struct sockaddr *)&from,&fromlen)) < 0) {
                perror("recvfrom error");
                return -1;
            }


            int                 sock_fd;
            int                 flag = 1;

            if ((sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
                perror("socket()");
                return -1;
            }
            if (setsockopt(sock_fd, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(int)) < 0) {
                perror("setsockopt() - IP_HDRINCL");
                return -1;
            }
            if(connect(sock_fd, &sin, sizeof(struct sockaddr_in))<0) {
                close(sockfd);
                perror("connect error");
                return -1;
            }
            ip = (struct ip *)buf;
            struct in_addr ip_src, ip_dst;
            ip_src.s_addr = inet_addr(orig_ip);
            ip_dst.s_addr = sender_addr.sin_addr.s_addr;
            ip->ip_src = ip_src;
            ip->ip_dst = ip_dst;
            iphdrlen = ip->ip_hl << 2; //求IP报文头长度,即IP报头长度乘4
            //icmp = (struct icmp *)(buf + iphdrlen); //越过IP头,指向ICMP报头
            //len -= iphdrlen;
            //将响应发给客户端
            printf("sendto client ");
            sendto(sock_fd, buf, len, 0, (struct sockaddr *)&sender_addr, sizeof(struct sockaddr));
            close(sock_fd);
  • 相关阅读:
    高级软件工程第八次作业LLS战队团队作业五
    Alpha阶段个人总结
    高级软件工程第七次作业:LLS战队Alpha敏捷冲刺7
    高级软件工程第七次作业:LLS战队Alpha敏捷冲刺6
    数独游戏界面功能
    数独棋盘
    调研《构建之法》指导下的全国高校的历届软工实践作品、全国互联网+竞赛、物联网竞赛、华为杯研究生作品赛、全国大学生服务外包赛等各类全国性大学生信息化相关的竞赛平台的历届作品
    高级软件工程课程的实践项目的自我目标
    Beta冲刺汇总博客
    团队作业9——第二次项目冲刺2(Beta阶段)
  • 原文地址:https://www.cnblogs.com/cklxmu/p/3976422.html
Copyright © 2011-2022 走看看