doudieheng5322 2016-07-16 16:19
浏览 151
已采纳

IPv6数据包头操作

I need to inspect and modify the IPv6 extension headers. So I set up a raw socket to listen for all IP packets on the local address.

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
", buf[:numRead])
    }
}

I tried all the Read*() methods on the connection but it seems like they just return the payload without the header. So my question is: How can I access the IPv6 header of a packet?

  • 写回答

1条回答 默认 最新

  • dsnw2651 2016-07-16 22:35
    关注

    Raw sockets with IPv6 are different compared to IPv4. Relevant for your case is RFC 3542. Note:

    Another difference from IPv4 raw sockets is that complete packets (that is, IPv6 packets with extension headers) cannot be sent or received using the IPv6 raw sockets API. Instead, ancillary data objects are used to transfer the extension headers and hoplimit information, as described in Section 6. Should an application need access to the complete IPv6 packet, some other technique, such as the datalink interfaces BPF or DLPI, must be used.


    You can find this out on your own. By running (and strace'ing) your program on my box for every packet I get:

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

    This means IP version = 4, IHL = 5 (20 bytes).

    When I try the same thing with IPv6 (i.e. your original code), I get something different every time:

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

    In this case every time the kernel is returning stuff starting directly with TCP (in this case the port is 50722, i.e 0xC622).

    Another interesting part should be noted in the 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))}
    }
    

    The header is stripped manually for IPv4 but not for IPv6: for IPv6 there is nothing to remove.


    Note, there are mechanisms that will return extra information (but by no means the whole packet). For example the IPV6_RECVPKTINFO socket option will give you access to:

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

    Similar options exist for the routing header option, hop limit etc.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?
  • ¥15 matlab(相关搜索:紧聚焦)
  • ¥15 基于51单片机的厨房煤气泄露检测报警系统设计
  • ¥15 Arduino无法同时连接多个hx711模块,如何解决?
  • ¥50 需求一个up主付费课程
  • ¥20 模型在y分布之外的数据上预测能力不好如何解决