• 盒子设备接口收发包的思考2


      接着昨天的继续看,说完收包再来说发包!  发包逻辑主要涉及到:tcp三次握手时:发送syn--TCP_SYN_SENT状态、syn_ack---TCP_NEW_SYN_RECV状态、TCP_LISTEN 、TCP_ESTABLISHED 等状态时发包

    首先看下 作为服务端时, TCP_LISTEN TCP_NEW_SYN_RECV 状态时发包处理:

    一、服务端收到syn 报文时,tcp 会回复syn_ack并设置为TCP_NEW_SYN_RECV  状态,那么此时发送报文和路由有什么关系呢?

    tcp_v4_conn_request 是回复syn_ack时处理函数;来看看主要涉及到路由的路由部分

    1、首先检查input_skb报文路由的特性,丢弃broadcast or multicast 

    2、收到第一步SYN的时候只是建立的连接控制块request_sock

     3、生成出口发包路由等

     4、build tcp pkt 然后send syn_ack pkt

     

    此时对于Tproxy逻辑来说,需要修改 tcp_make_synack 以及ip_send_pkt;一般都会根据ireq->no_srccheck 标志来检查是否使用tproxy 逻辑发送报文;

    如果使用tproxy 发送报文,此时需要make_pkt_send 根据自己需要发送,同时也是绑定特定接口发出dev_queue_xmit,所以此时生成的route 无用;

    二、服务端收到ack报文时,从TCP_NEW_SYN_RECV变为TCP_ESTABLISHED,那么此时发送报文和路由有什么关系呢?

         三次握手的第二阶段,服务器发送synack后,会进入TCP_NEW_SYN_RECV状态,并插入ehash中。 收到握手最后一个ack后,会找到TCP_NEW_SYN_RECV状态的req,然后创建一个新的sock进入TCP_SYN_RECV状态,最终进入TCP_ESTABLISHED状态. 并放入accept队列通知select/epoll 

      在tcp_child_process中调用tcp_rcv_state_process来处理TCP_SYN_RECV状态的child sock。并进入TCP_ESTABLISHED状态

     tcp_rcv_state_process 在此时条件下主要逻辑为:  TCP_SYN_RECV------>TCP_ESTABLISHED 唤醒epfd 初始化tcp 相关参数 同时检查是否有需要发送数据

     

     检查发送报文是,tcp状态为TCP_ESTABLISHED

     

    TCP TCP_ESTABLISHED 状态时 发报文和路由缓存的关系

    三、TCP 为TCP_ESTABLISHED 状态时 发报文和路由缓存的关系

    此时tcp 发送报文会调用ip_queue_xmit 发送ip报文,ip层会涉及到路由:

     最后根据路由调用:ip_output()或者ip_mc_output() 封装发送ip层报文

    所以对于上述场景: 在tproxy 的使用场景下,完全是可以不需要rt,因为此时发包时肯定指定接口了!!wan口和lan口是一对接口,lan口进wan出,wan口进lan口出-----

    再来看看tproxy  客户端场景下的分析:

    一:客户端主动发包建立三次握手,发出syn ---->TCP_SYN_SENT

    connect 系统调用主要函数 tcp_v4_connect为:

     

    但是对于主动发包时:此时使用的socket 只是随便create的一个socket,由于其src_ip dst_ip 是外部client 以及服务器ip,所以发包时要根据原始session 填充build_tcp_ip_pkt;

    此时肯定不能走原始的tcp_connect逻辑需要重新修改connect 逻辑:

    sk=socket();

    bind(clinet_ip,clinet_port)

    set_opt(transparent, );

    connect(server_ip  server port)

    所以sys_connect:逻辑中需要 根据client_ip_port  server_ip_port   找到 原始 established_socket;

    然后copy 原始src_mac dst_mac input_ifindex;找出output_ifdex;设置 bind==> inet->sk.sk_bound_dev_if = ifindex;

    原始的connect 会调用ip_route_slow 查找路由,此时bind了接口,所以路由出接口就知道了,

    相当于此时可以不需要路由rt;

    接着inet_hash_connect  insert 到established散列表 方便收到ack 的时候查找,目前只有established hash 和listen hash

    封装tcp 后调用ip_queue_xmit 发送封装ip 层报文然后发送------

    可以此时也可以不需要路由;因为都已经bind ifindex 了  但是发包时sk的src ip dst ip port等要设置正确

    二:客户端收到syn_ack 发出ack时, 从TCP_SYN_SENT---->TCP_ESTABLISHED

    也就是tcp_rcv_state_process的逻辑

    可知 同上述一样  可以不需要路由rt

    所以:

    目前认为在tproxy下: wan口和lan口是一对,缺少路由无所谓!! 去掉路由逻辑应该也非常方便

    只需要判断sk 是否为transparent;

    bool tproxy_sk_is_transparent(struct sock *sk)
    {
        switch (sk->sk_state) {
        case TCP_TIME_WAIT:
            if (inet_twsk(sk)->tw_transparent)
                return true;
            break;
        case TCP_NEW_SYN_RECV:
            if (inet_rsk(inet_reqsk(sk))->no_srccheck)
                return true;
            break;
        default:
            if (inet_sk(sk)->transparent)
                return true;
        }
    
        return false;
    }
    http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子
  • 相关阅读:
    linux下的socket编程(3)--server端的简单示例
    高级I/O函数
    补充:memset透彻分析
    空间复杂度为0的数据交换
    排序算法一:直接插入排序
    [Github]watch和star的区别
    计算机网络总结(四)
    计算机网络总结(三)
    Java集合
    计算机网络总结(二)
  • 原文地址:https://www.cnblogs.com/codestack/p/14491790.html
Copyright © 2020-2023  润新知