盒子设备接口收发包的思考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的胖子
原文地址:https://www.cnblogs.com/codestack/p/14491790.html