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

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 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题