鏈路層原始套接字

創(chuàng)建套接字的函數(shù)原型如下

int socket(int domain, int type, int protocol);

對于鏈路層原始套接字來說,第一個參數(shù)指定協(xié)議族類型為PF_PACKET络拌,第二個參數(shù)type可以設(shè)置為SOCK_RAW或SOCK_DGRAM俭驮,第三個參數(shù)是協(xié)議類型(該參數(shù)只對報(bào)文接收有意義)。

第三個參數(shù)protocol的用法春贸,如下表格從參考連接截圖


image.png

表1中protocol的取值中有兩個值是比較特殊的混萝。當(dāng)protocol為ETH_P_ALL時(shí),表示能夠接收本機(jī)收到的所有二層報(bào)文(包括IP, ARP, 自定義二層報(bào)文等)萍恕,同時(shí)這種類型套接字還能夠?qū)⑼獍l(fā)的報(bào)文再收回來逸嘀。當(dāng)protocol為0時(shí),表示該套接字不能用于接收報(bào)文允粤,只能用于發(fā)送崭倘。

本文重點(diǎn)從代碼角度解釋上面的兩個特殊值

當(dāng)protocol為0時(shí),表示該套接字不能用于接收報(bào)文维哈,只能用于發(fā)送.
當(dāng)protocol為ETH_P_ALL時(shí)绳姨,表示能夠接收本機(jī)收到的所有二層報(bào)文
(包括IP, ARP, 自定義二層報(bào)文等),同時(shí)這種類型套接字還能夠?qū)⑼獍l(fā)的報(bào)文再收回來(這句話是不對的阔挠,至少在我看的內(nèi)核代碼上不能將外發(fā)的報(bào)文再收回來)飘庄。

協(xié)議棧收發(fā)包入口

協(xié)議棧收包入口

static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
    ...
    //遍歷鏈表ptype_all將報(bào)文復(fù)制一份調(diào)用每個鏈表節(jié)點(diǎn)的func
    list_for_each_entry_rcu(ptype, &ptype_all, list) {
        if (!ptype->dev || ptype->dev == skb->dev) {
            if (pt_prev)
                ret = deliver_skb(skb, pt_prev, orig_dev);
            pt_prev = ptype;
        }
    }
    ...
    //ptype_base為hash鏈表,其將相同type的ptype加入同一個鏈
    //表购撼。這里根據(jù)type遍歷鏈表跪削,并調(diào)用ptype->func函數(shù)
    type = skb->protocol;
    list_for_each_entry_rcu(ptype,
            &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
        if (ptype->type == type &&
            (ptype->dev == null_or_dev || ptype->dev == skb->dev ||
             ptype->dev == orig_dev)) {
            if (pt_prev)
                ret = deliver_skb(skb, pt_prev, orig_dev);
            pt_prev = ptype;
        }
    }

協(xié)議棧發(fā)包入口

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq)
    ...
        if (!list_empty(&ptype_all))
            dev_queue_xmit_nit(skb, dev);
    ...

static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
    ...
    //遍歷鏈表ptype_all將報(bào)文復(fù)制一份調(diào)用每個鏈表節(jié)點(diǎn)的func
    list_for_each_entry_rcu(ptype, &ptype_all, list) {
        //注意這里的注釋,從不會將報(bào)文發(fā)回給原始socket迂求,即
        //socket收不到自己發(fā)出去的報(bào)文
        /* Never send packets back to the socket
         * they originated from - MvS (miquels@drinkel.ow.org)
         */
        if ((ptype->dev == dev || !ptype->dev) &&
            (!skb_loop_sk(ptype, skb))) {
            if (pt_prev) {
                deliver_skb(skb2, pt_prev, skb->dev);
                pt_prev = ptype;
                continue;
            }
    }
    ...

從上面收發(fā)包入口函數(shù)可看到用到了如下兩個全局變量碾盐,用來保存注冊的ptype,注冊函數(shù)為dev_add_pack

struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
struct list_head ptype_all __read_mostly;   /* Taps */

void dev_add_pack(struct packet_type *pt)
{
    struct list_head *head = ptype_head(pt);

    spin_lock(&ptype_lock);
    list_add_rcu(&pt->list, head);
    spin_unlock(&ptype_lock);
}

static inline struct list_head *ptype_head(const struct packet_type *pt)
{
    if (pt->type == htons(ETH_P_ALL))
        return &ptype_all;
    else
        return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
}

創(chuàng)建packet_create socket

static int packet_create(struct net *net, struct socket *sock, int protocol, int kern)
    po = pkt_sk(sk);
    sk->sk_family = PF_PACKET;
    po->num = proto;
    po->xmit = dev_queue_xmit;

    po->prot_hook.af_packet_priv = sk;

    //proto 非0才會注冊收包揩局,即只能發(fā)送報(bào)文
    if (proto) {
        po->prot_hook.type = proto;
        register_prot_hook(sk);
            dev_add_pack(&po->prot_hook);
    }

解釋

當(dāng)protocol為0時(shí)毫玖,不會調(diào)用dev_add_pack注冊ptype,所以也就不能接收報(bào)文了凌盯。
當(dāng)protocol為ETH_P_ALL時(shí)付枫,會將ptype注冊到ptype_all鏈表,協(xié)議
棧收包/發(fā)包入口都會遍歷ptype_all鏈表執(zhí)行ptype->func驰怎,但是發(fā)包時(shí)是收不回來本socket發(fā)送的報(bào)文的阐滩。

參考

Linux原始套接字實(shí)現(xiàn)分析-albin_yang-ChinaUnix博客

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市县忌,隨后出現(xiàn)的幾起案子掂榔,更是在濱河造成了極大的恐慌继效,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件装获,死亡現(xiàn)場離奇詭異瑞信,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)饱溢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門喧伞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绩郎,你說我怎么就攤上這事∥坛眩” “怎么了肋杖?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挖函。 經(jīng)常有香客問我状植,道長,這世上最難降的妖魔是什么怨喘? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任津畸,我火速辦了婚禮,結(jié)果婚禮上必怜,老公的妹妹穿的比我還像新娘肉拓。我一直安慰自己,他們只是感情好梳庆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布暖途。 她就那樣靜靜地躺著,像睡著了一般膏执。 火紅的嫁衣襯著肌膚如雪驻售。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天更米,我揣著相機(jī)與錄音欺栗,去河邊找鬼。 笑死征峦,一個胖子當(dāng)著我的面吹牛迟几,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播眶痰,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瘤旨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了竖伯?” 一聲冷哼從身側(cè)響起存哲,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤因宇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后祟偷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體察滑,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年修肠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贺辰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡嵌施,死狀恐怖饲化,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吗伤,我是刑警寧澤吃靠,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站足淆,受9級特大地震影響巢块,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜巧号,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一族奢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丹鸿,春花似錦越走、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至掺涛,卻和暖如春庭敦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背薪缆。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工秧廉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拣帽。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓疼电,卻偏偏與公主長得像,于是被迫代替她去往敵國和親减拭。 傳聞我的和親對象是個殘疾皇子蔽豺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容