功能:就是一個簡單的通過 netlink 將用戶發層發送的資料讓內核接收到
問題現象:如標題
先看一下代碼,再看我的控制臺輸出會比較能理解
用戶層的核心代碼就是下面這兩句。
memcpy(NLMSG_DATA(nlh), compelte_cmd, strlen(compelte_cmd));
ret = sendto(skfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct sockaddr_nl));
內核層,從netlink接收用戶層發送來的資料的核心代碼:
nlh = nlmsg_hdr(skb);
umsg = NLMSG_DATA(nlh);
if (umsg) {
len = strlen(umsg);
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
//這里為了搞清楚接收到的奇怪字符到底是什么,做了以下處理(就是從字串末尾依次刪減字符)
umsg[len - 1] = 0;
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
umsg[len - 2] = 0;
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
umsg[len - 3] = 0;
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
umsg[len - 4] = 0;
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
umsg[len - 5] = 0;
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
umsg[len - 6] = 0;
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
umsg[len - 7] = 0;
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
umsg[len - 8] = 0;
printk(KERN_EMERG"len=%d\n",strlen(umsg));
printk(KERN_EMERG"kernel recv from user: [%s]\n", umsg);
}
于是,正常情況下的用戶層字符輸入會被內核完整捕獲:
(【swconfig dev switch0 get】 是我用戶層的觸發命令,這個可以不用在意,重要的是后面的數字引數,以及除錯資訊)
傳輸20個字符的情況:
root@Ruijie:~# swconfig dev switch0 get 12345678901234567890
[ 52.130000] len=20
[ 52.130000] kernel recv from user: [12345678901234567890]
[ 52.140000] len=19
[ 52.140000] kernel recv from user: [1234567890123456789]
[ 52.150000] len=18
[ 52.150000] kernel recv from user: [123456789012345678]
[ 52.150000] len=17
[ 52.160000] kernel recv from user: [12345678901234567]
[ 52.160000] len=16
[ 52.160000] kernel recv from user: [1234567890123456]
[ 52.170000] len=15
[ 52.170000] kernel recv from user: [123456789012345]
[ 52.180000] len=14
[ 52.180000] kernel recv from user: [12345678901234]
[ 52.180000] len=13
[ 52.190000] kernel recv from user: [1234567890123]
[ 52.190000] len=12
[ 52.190000] kernel recv from user: [123456789012]
recvfrom...
recv len:0
root@Ruijie:~#
以上 20個字符沒有例外。
現在看一下傳輸 24個字符的情況:
root@Ruijie:~# swconfig dev switch0 get 123456789012345678901234
[ 543.140000] len=28 //<--注意這里!! 明明引數只有24個字符這里居然識別到28個字符?? 而且以下情況極為詭異,輸出的字串末尾不知道跟了什么東西,連右括號‘]’都沒了,不是我排版亂了,而是輸出結果就是這樣!
[ 543.140000] kernel recv from user: [123456789012345678901234
[ 543.150000] len=27
[ 543.150000] kernel recv from user: [123456789012345678901234
[ 543.160000] len=26
[ 543.160000] kernel recv from user: [123456789012345678901234[ 543.160000] len=25
[ 543.170000] kernel recv from user: [123456789012345678901234]
[ 543.170000] len=24
[ 543.180000] kernel recv from user: [123456789012345678901234] //<--直到洗掉到只剩24個字符的時候,字串末尾的未知字符消失了,輸出也恢復正常了。實在不解
[ 543.180000] len=23
[ 543.180000] kernel recv from user: [12345678901234567890123]
[ 543.190000] len=22
[ 543.190000] kernel recv from user: [1234567890123456789012]
[ 543.200000] len=21
[ 543.200000] kernel recv from user: [123456789012345678901]
[ 543.210000] len=20
[ 543.210000] kernel recv from user: [12345678901234567890]
recvfrom...
recv len:0
root@Ruijie:~#
以上怪異現象只有在字串長度為 24~27之間(含24,27)的時候才會出現,大于27字符的時候則又沒有這種怪異的現象
再看一下傳輸28個字符的情況:
root@Ruijie:~# swconfig dev switch0 get 1234567890123456789012345678
[ 1599.520000] len=28
[ 1599.530000] kernel recv from user: [1234567890123456789012345678]
[ 1599.530000] len=27
[ 1599.540000] kernel recv from user: [123456789012345678901234567]
[ 1599.540000] len=26
[ 1599.540000] kernel recv from user: [12345678901234567890123456]
[ 1599.550000] len=25
[ 1599.550000] kernel recv from user: [1234567890123456789012345]
[ 1599.560000] len=24
[ 1599.560000] kernel recv from user: [123456789012345678901234]
[ 1599.570000] len=23
[ 1599.570000] kernel recv from user: [12345678901234567890123]
[ 1599.580000] len=22
[ 1599.580000] kernel recv from user: [1234567890123456789012]
[ 1599.580000] len=21
[ 1599.590000] kernel recv from user: [123456789012345678901]
[ 1599.590000] len=20
[ 1599.590000] kernel recv from user: [12345678901234567890]
recvfrom...
recv len:0
root@Ruijie:~#
可以看到傳輸28個字符的時候則完全正常。
情況就是這樣,有沒有人知道這是什么原因呢?
用戶層代碼我確認是發送了完整的字串,特殊字符的出現絕對是內核這邊接收的時候才出現的。
難道是內核從netlink訊息體中獲取資料的時候指標例外了?
nlh = nlmsg_hdr(skb);
umsg = NLMSG_DATA(nlh);
上面這個獲取 netlink 訊息體的代碼我嘗試過替換成下面這種方式,但是問題依舊。
nlh = (struct nlmsghdr *)skb->data;
望解惑
uj5u.com熱心網友回復:
網路傳輸有一個最小以太網報文的要求64位元組,以太網頭部14位元組,IP報文頭部典型20位元組;
因此是正文最小是30位元組。
如果IP報文頭部是22個位元組,正文最小就是28位元組。
如果用戶發送的以太網報文長度小于64位元組,網卡可以選擇自己補齊、或者發送更小報文、或者丟棄報文。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/46229.html
標籤:內核源代碼研究區
