原文链接,欢迎大家关注我的github
调用taskAddContainer->taskInterceptContainer->programDP->DPCtrlAddTapPort为所有非host模式的容器向dp传送
DPAddTapPortReq对象数据.(当切换成保护模式后,都会调用DPCtrlDelTapPort),dp侧收到ctrl_add_tap_port信息后创建对应的
packet mmap对该容器的网络连接进行收集学习,
dp侧调用dp_ctrl_update_connects方法向agent传送网络连接, agent侧通过grpc的方式调用sendConnections方法将网络连接给
controller,controller侧存储在consul中 ;
相关日志如下 :
dp侧收到ctrl_add_tap_port数据后,执行路径如下dp_ctrl_handler->dp_ctrl_add_tap_port->dp_data_add_tap->dp_alloc_context-
>dp_open_socket(创建AF_PACKET的socket并绑定容器的网络接口eth0)->dp_ring_v1(通过setsockopt创建的接收的环形缓冲区-)
>dp_rx_v1( 对于缓冲区中的数据,循环调用dpi_recv_packet处理)→dpi_recv_packet(核心函数)
1.dp_open_socket主要调用逻辑如下:
2.dpi_recv_packet中实现网络数据包的收集上报与管控, 对数据包进行解析后,形成相应的网络连接,主要调用函数如下:
3.dpi_inspect_etherne主要调用函数如下:
4.dp_ctrl_loop:实现轮询更新威胁日志、域名转换ip、网络连接、应用的mac地址信息
5.dp_ctrl_update_connects: 在dp_ctrl_loop方法中被调用,通过send_connects方法实现向agent侧发送解析后的网络连接;
6.dp_ctrl_notify_ctrl: 通过sendto方法实现向agent侧发送相关信息(网络连接、威胁日志、域名转换等)
通过agent/probe/socket.go/下的getNewConnections方法获取host模式的网络连接, agent侧通过grpc的方式调用sendConnections方法将网络连接给controller,controller侧存储在consul中。
1.当enforce容器与dp连接时agent侧会调用taskDPConnect方法用于网络规则相关信息的的初始化以及调用DPCtrlAddSrvcPort方法实现配置连接vth-neuv网络接口的packet_mmap用于后续网络管控。
2.当切换成保护模式后,都会在programDP中调用DPCtrlDelTapPort 和DPCtrlAddMAC实现对原有的context进行释放以及mac地址的更
新。
学习模式→保护模式后 ,agent监听到consul中网络的策略改变,主要路径networkDerivedProc->systemConfigPolicy→updateContainerPolicyMode→changeContainerWire( 调用programUpdatePairs方法为被保护的容器在
Enforcer中创建进出的Veth pair )->programBridge->FwdPortPair( 创建新的tc规则。 过滤单播数据包到vth-neuv网络接口上进行管控)
写在前面:
1.agent侧连接dp时会在taskDPConnect方法中调用DPCtrlAddSrvcPort方法实现配置连接vth-neuv网络接口的packet_mmap;
2.保护模式会调用DPCtrlDelTapPort方法 ,流量数据包会经过vth-neuv网络接口,dp侧通过vth-neuv网络接口的packet mmap用于对数据
包进行管控,该packet mmap会设置用于传输的的环形缓冲区(PACKET_TX_RING)实现发包的功能;
dp侧主要流程如下:
dpi_policy_reeval函数详细逻辑:
通过session中的policy同数据包进行规则匹配确定数据包action执行相应操作。
核心在于packet中的网络规则通过g_ep_map传入(即(dpi_policy_hdl_t *)p->ep→policy_hdl),通过解析packet得到(sip,dip,dport,proto,
app)组成key(dpi_rule_key_t)。
将key同hdl中的policy_map和range_policy_map进行匹配,如果匹配到得到相应的action,如果匹配不到使用hdl中默认的action。
拿到action后针对不同类型的action进行拒绝和通过,udp拒绝直接丢包,tcp拒绝需要发送双向重置包到tx缓冲区,通过的请求会转发到tx缓冲区。
1 对于Tcp协议的主要管控路径:dpi_recv_packet-》dpi_parse_ethernet( 弄清第三层第四层网络协议方向后进行解析, 以便如果数据包中
存在任何威胁,可以正确记录日志)-》dpi_inspect_ethernet-》dpi_session_lookup(查找对应的session)-》dpi_pkt_proto_tracker(关
于tcp、udp、icmp等的跟踪器、记录相关行为并且判断部分内置威胁检测)-》dpi_pkt_proto_parser(协议解析)-》
dpi_pkt_policy_reeval-》存在不匹配的规则或者不知名的IP地址并且动作为deny以及tcp传输协议则调用dpi_inject_reset-》 dpi_inject_rese
t_by_session( 将tcp的标志设置为RST tcph->th_flags = TH_RST,通过双向fake tcp rst包重置目标连接双方的网络连接 ) --》send_packet
==dp_send_packet -》 ctx->ring.tx(ctx, pkt, len, context->large_frame):发送数据包到传输的环形的缓冲区 -》传输的缓冲区将数据包
通过tc发送给容器或者主机
2 对于Udp、Icmp协议的主要管控路径: dpi_recv_packet-》 dpi_parse_ethernet( 弄清第三层第四层网络协议方向后进行解析, 以便如果数
据包中存在任何威胁,可以正确记录日志)-》 dpi_inspect_ethernet-》dpi_session_lookup(查找对应的session)-》
dpi_pkt_proto_tracker(关于tcp、udp、icmp等的跟踪器、记录相关行为并且判断部分内置威胁检测)-》dpi_pkt_proto_parser(协议解
析)-》dpi_pkt_policy_reeval-》动作设置DPI_ACTION_BLOCK-》动作为DROP、BLOCK、RESET时不会调用send_packet则默认阻塞
学习模式→保护模式后 ,agent监听到consul中网络的策略改变,调用networkDerivedProc->systemConfigPolicy-
>updateContainerPolicyMode→changeContainerWire->programProxyMeshDP(网格代理的容器tapProxymesh为true)
与非服务网格代理的容器相同,都会通过Enforceer做代理创建对应veth pair以及tc规则,这里不重复介绍。
在programProxyMeshDP方法中实现在容器的命名空间中使用NFQUEUE设置iptable规则,dp侧创建nfq句柄(nfq_open)
流程实现图如下:
网络这一部分涉及到的知识比较多,这里主要说一下主要流程和主要函数,如果大家感兴趣欢迎私聊;