軟裝設(shè)計(jì)圖 效果圖溫州seo教程
背景
? ? ? ? 今天遇到一個(gè)詭異的現(xiàn)象,當(dāng)接口附加一個(gè)IP時(shí),主IP業(yè)務(wù)正常,附加IP死活不行,tcpdump抓包確可以正常抓到到業(yè)務(wù)的報(bào)文,但是在PREROUTING raw添加規(guī)則確沒(méi)有命中,說(shuō)明報(bào)文沒(méi)有到netfilter框架內(nèi),Scapy打流測(cè)試,通過(guò)bpftrace 跟蹤kfree_skb,沒(méi)有捕獲大量的kfree_skb 調(diào)用,才引發(fā)今天的問(wèn)題,數(shù)據(jù)報(bào)文去哪兒了?
結(jié)論
? ? ? ? 由于上層設(shè)備發(fā)送報(bào)文時(shí),將附加IP的MAC地址填錯(cuò)導(dǎo)致,但是tcpdump可以明確報(bào)文已經(jīng)到了主機(jī),但是為什么卻沒(méi)有往netfilter框架遞送,bpftrace 為什么沒(méi)有捕獲大量的kfree_skb?? 簡(jiǎn)單的講錯(cuò)誤的MAC地址,正確的IP 是否可以正常通信?為什么?
內(nèi)核源碼分析
? ? ? ? 本文使用內(nèi)核版本 5.10, 網(wǎng)卡驅(qū)動(dòng) e1000e
? ? ? ? 我們知道當(dāng)網(wǎng)卡工作在直接模式(Direct Model)時(shí),網(wǎng)卡只接收自己MAC地址的幀,此模式下通過(guò)scapy打流不匹配的目的mac地址時(shí),數(shù)據(jù)幀直接被網(wǎng)卡層面丟棄,bpftrace 此時(shí)無(wú)法捕獲kfree_skb事件。
? ? ? ? 當(dāng)使用tcpdump工具時(shí)會(huì)將網(wǎng)卡設(shè)置為混雜模式(Promiscuous Model),不匹配自己的MAC地址也會(huì)接收交給網(wǎng)卡驅(qū)動(dòng)處理。
/*** e1000_receive_skb - helper function to handle Rx indications* @adapter: board private structure* @netdev: pointer to netdev struct* @staterr: descriptor extended error and status field as written by hardware* @vlan: descriptor vlan field as written by hardware (no le/be conversion)* @skb: pointer to sk_buff to be indicated to stack**/
static void e1000_receive_skb(struct e1000_adapter *adapter,struct net_device *netdev, struct sk_buff *skb,u32 staterr, __le16 vlan)
{u16 tag = le16_to_cpu(vlan);e1000e_rx_hwtstamp(adapter, staterr, skb);skb->protocol = eth_type_trans(skb, netdev);if (staterr & E1000_RXD_STAT_VP)__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);napi_gro_receive(&adapter->napi, skb);
}
這里e1000e網(wǎng)卡驅(qū)動(dòng)接收?qǐng)?bào)文,此處注意eth_type_trans(skb, netdev)方法
/*** eth_type_trans - determine the packet's protocol ID.* @skb: received socket data* @dev: receiving network device** The rule here is that we* assume 802.3 if the type field is short enough to be a length.* This is normal practice and works for any 'now in use' protocol.*/
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{unsigned short _service_access_point;const unsigned short *sap;const struct ethhdr *eth;skb->dev = dev;skb_reset_mac_header(skb);eth = (struct ethhdr *)skb->data;skb_pull_inline(skb, ETH_HLEN);/* 此處目的MAC不是設(shè)備DEV地址時(shí),命中條件 */if (unlikely(!ether_addr_equal_64bits(eth->h_dest,dev->dev_addr))) {/* 檢測(cè)目的MAC是否為多播或者組播 */if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) {if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))skb->pkt_type = PACKET_BROADCAST;elseskb->pkt_type = PACKET_MULTICAST;} else {skb->pkt_type = PACKET_OTHERHOST;}}if (likely(eth_proto_is_802_3(eth->h_proto)))return eth->h_proto;.....
}
當(dāng)我們的目的MAC地址與自身dev地址不匹配時(shí),會(huì)將pkt_type =?PACKET_OTHERHOST 然后返回eth->proto, 這里我們使用的IP報(bào)文,也就是將來(lái)會(huì)使用ip_rcv()處理。
然后通過(guò)NAPI接口,__netif_receive_skb_core,等一系列調(diào)用最終調(diào)用到ip_rcv_core()
/** Main IP Receive routine.*/
static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net)
{const struct iphdr *iph;u32 len;/* When the interface is in promisc. mode, drop all the crap* that it receives, do not try to analyse it.*/if (skb->pkt_type == PACKET_OTHERHOST)goto drop;......drop:kfree_skb(skb);
out:return NULL;
}
這里有明確的注釋說(shuō)明,混雜模式的報(bào)文即pkt_type為PACKET_OTHERHOST值,直接丟棄,并且此處的drop,內(nèi)核協(xié)議棧層面并沒(méi)有做任何的丟包統(tǒng)計(jì)。
總結(jié)
經(jīng)過(guò)分析我們可以總結(jié)我們遇到的問(wèn)題,
1,通過(guò)scapy打流測(cè)試,為什么bpftrace沒(méi)有捕獲到大量的kfree_skb事件?
? ? ?這是因?yàn)榫W(wǎng)卡工作在直接模式(Direct Model)網(wǎng)卡將目的MAC不是自己的直接丟棄,驗(yàn)證這個(gè)想象,可以直接使用tcpdump 工具抓包,此時(shí)bpftrace 可以捕獲大量的kfree_skb事件。
2,tcpdump 捕獲到去往自己IP的報(bào)文,為什么沒(méi)有到netfilter框架?
? ? ? ?這是因?yàn)閠cpdump將網(wǎng)卡設(shè)置為混雜模式(Promiscuous Model)網(wǎng)卡驅(qū)動(dòng)接收?qǐng)?bào)文并將報(bào)文類型置為PACKET_OTHERHOST,當(dāng)ip_rcv_core()接收后直接丟棄,并且沒(méi)有在任何地方做丟包統(tǒng)計(jì)的動(dòng)作。
感受
? ? 工作中遇到的每個(gè)小問(wèn)題,背后都蘊(yùn)藏著大量知識(shí),只有平時(shí)多積累總結(jié),才能游刃有余解決所面對(duì)的問(wèn)題。