2016-07-16 35 views
2

我需要檢查和修改IPv6擴展報頭。所以我設置了一個原始套接字來監聽本地地址上的所有IP數據包。IPv6數據包報頭操作

package main 

import (
    "log" 
    "net" 
) 

func main() { 
    c, err := net.ListenIP("ip6:tcp", &net.IPAddr{ 
     IP: net.IPv6loopback, 
     Zone: "", 
    }) 
    if err != nil { 
     panic(err) 
    } 

    buf := make([]byte, 1024) 
    for { 
     numRead, ipaddr, err := c.ReadFromIP(buf) 
     log.Print(numRead, ipaddr, err) 
     log.Printf("% X\n", buf[:numRead]) 
    } 
} 

我嘗試了所有的連接上Read*()方法,但是好像他們剛剛回歸的有效載荷沒有頭。 所以我的問題是:如何訪問數據包的IPv6標頭?

+0

有一點要注意的是,IPv6擴展頭很少被使用,並且,不幸的是,路徑中的許多ISP會阻止或剝離擴展頭,因爲它們可用於攻擊。 –

回答

3

與IPv4相比,使用IPv6的原始套接字不同。有關你的情況是RFC 3542。注:

從IPv4的原始套接字的另一個區別是是完整的數據包(即具有擴展頭的IPv6數據包)不能使用IPv6原始套接字API來發送或接收。而是使用輔助數據對象傳輸擴展頭和跳轉限制信息,如第6節所述。如果應用程序需要訪問完整的IPv6數據包,則其他一些技術(如數據鏈接接口BPF或DLPI)必須使用。


你可以找到這個在你自己。通過運行(與strace'ing)你的程序在我的箱子爲每個數據包,我得到:

recvfrom(3, "\x45\x00\x00\x3c\x6a\x7d... 
       ^^ 

這意味着IP版本= 4,IHL = 5(20個字節)。

當我嘗試使用IPv6(即原來的代碼)同樣的事情,我得到不同的東西,每次:

recvfrom(3, "\xc6\x22\x00\x50\x4d 

在這種情況下,每一個內核被返回的東西直接與TCP開始時間(在此如果端口是50722,即0xC622)。

另一個有趣的部分應該在sources注意:

switch sa := sa.(type) { 
case *syscall.SockaddrInet4: 
    addr = &IPAddr{IP: sa.Addr[0:]} 
    n = stripIPv4Header(n, b) 
case *syscall.SockaddrInet6: 
    addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))} 
} 

頭手動對IPv4但不能剝奪對IPv6:IPv6的沒有什麼可以取下。


請注意,有些機制會返回額外的信息(但絕不是整個數據包)。例如,IPV6_RECVPKTINFO套接字選項會給你訪問:

struct in6_pktinfo { 
    struct in6_addr ipi6_addr; /* src/dst IPv6 address */ 
    unsigned int ipi6_ifindex; /* send/recv interface index */ 
}; 

類似的選項存在路由報頭選項,跳數限制等

+0

感謝您的回答。我已經注意到標題被刪除的源代碼部分,但不知道它的原因。所以我想這只是不可能做'淨'包?! – fl0cke

+0

@ fl0cke我認爲這裏的淨包是不夠的。您可能會脫離Linux特有的['PF_PACKET'](http://man7.org/linux/man-pages/man7/packet.7.html)或BPF(可在多個Unix上使用)。 – cnicutar