zoukankan      html  css  js  c++  java
  • golang 定期发送 RA 报文

    源码:

    package  main
    
    import (
        "context"
        "errors"
        "flag"
        "fmt"
        "github.com/mdlayher/ndp"
        "io"
        "log"
        "net"
        "os"
        "strings"
        "time"
    )
    
    func main() {
        var (
            ifiFlag    = flag.String("i", "", "network interface to use for NDP communication (default: automatic)")
            addrFlag   = flag.String("a", string(ndp.LinkLocal), "address to use for NDP communication (unspecified, linklocal, uniquelocal, global, or a literal IPv6 address)")
        )
    
        flag.Parse()
    
        ll := log.New(os.Stderr, "ndp> ", 0)
        if flag.NArg() > 1 {
            ll.Fatalf("too many args on command line: %v", flag.Args()[1:])
        }
    
        ifi, err := findInterface(*ifiFlag)
        if err != nil {
            ll.Fatalf("failed to get interface: %v", err)
        }
    
        c, _, err := ndp.Listen(ifi, ndp.Addr(*addrFlag))
        if err != nil {
            ll.Fatalf("failed to open NDP connection: %v", err)
        }
        defer c.Close()
    
        for  {
            if err := doRA(c, ifi.HardwareAddr); err != nil {
                // Context cancel means a signal was sent, so no need to log an error.
                if err == context.Canceled {
                    os.Exit(1)
                }
    
                ll.Fatal(err)
            }
            time.Sleep(1*time.Second)
        }
    }
    
    // findInterface attempts to find the specified interface.  If name is empty,
    // it attempts to find a usable, up and ready, network interface.
    func findInterface(name string) (*net.Interface, error) {
        if name != "" {
            ifi, err := net.InterfaceByName(name)
            if err != nil {
                return nil, fmt.Errorf("could not find interface %q: %v", name, err)
            }
    
            return ifi, nil
        }
    
        ifis, err := net.Interfaces()
        if err != nil {
            return nil, err
        }
    
        for _, ifi := range ifis {
            // Is the interface up and not a loopback?
            if ifi.Flags&net.FlagUp != 1 || ifi.Flags&net.FlagLoopback != 0 {
                continue
            }
    
            // Does the interface have an IPv6 address assigned?
            addrs, err := ifi.Addrs()
            if err != nil {
                return nil, err
            }
    
            for _, a := range addrs {
                ipNet, ok := a.(*net.IPNet)
                if !ok {
                    continue
                }
    
                // Is this address an IPv6 address?
                if ipNet.IP.To16() != nil && ipNet.IP.To4() == nil {
                    return &ifi, nil
                }
            }
        }
    
        return nil, errors.New("could not find a usable IPv6-enabled interface")
    }
    func doRA(c *ndp.Conn, addr net.HardwareAddr) error {
        ll := log.New(os.Stderr, "ndp ra> ", 0)
    
        prefix:= net.ParseIP("fe80::100:")
    
        // This tool is mostly meant for testing so hardcode a bunch of values.
        m := &ndp.RouterAdvertisement{
            CurrentHopLimit:           64,
            RouterSelectionPreference: ndp.Medium,
            RouterLifetime:            30 * time.Second,
            Options: []ndp.Option{
                &ndp.PrefixInformation{
                    PrefixLength:                   64,
                    AutonomousAddressConfiguration: true,
                    ValidLifetime:                  60 * time.Second,
                    PreferredLifetime:              30 * time.Second,
                    Prefix:                         prefix,
                },
                &ndp.LinkLayerAddress{
                    Direction: ndp.Source,
                    Addr:      addr,
                },
            },
        }
    
        printMessage(ll, m, net.ParseIP("::"))
    
        if err := c.WriteTo(m, nil, net.IPv6linklocalallnodes); err != nil {
            return fmt.Errorf("failed to send router advertisement: %v", err)
        }
    
        return nil
    }
    
    func printMessage(ll *log.Logger, m ndp.Message, from net.IP) {
        switch m := m.(type) {
        case *ndp.RouterAdvertisement:
            printRA(ll, m, from)
        default:
            ll.Printf("%s %#v", from, m)
        }
    }
    
    func printRA(ll *log.Logger, ra *ndp.RouterAdvertisement, from net.IP) {
        var flags []string
        if ra.ManagedConfiguration {
            flags = append(flags, "managed")
        }
        if ra.OtherConfiguration {
            flags = append(flags, "other")
        }
        if ra.MobileIPv6HomeAgent {
            flags = append(flags, "mobile")
        }
        if ra.NeighborDiscoveryProxy {
            flags = append(flags, "proxy")
        }
    
        var s strings.Builder
        writef(&s, "router advertisement from: %s:
    ", from)
    
        if ra.CurrentHopLimit > 0 {
            writef(&s, "  - hop limit:        %d
    ", ra.CurrentHopLimit)
        }
        if len(flags) > 0 {
            writef(&s, "  - flags:            [%s]
    ", strings.Join(flags, ", "))
        }
    
        writef(&s, "  - preference:       %s
    ", ra.RouterSelectionPreference)
    
        if ra.RouterLifetime > 0 {
            writef(&s, "  - router lifetime:  %s
    ", ra.RouterLifetime)
        }
        if ra.ReachableTime != 0 {
            writef(&s, "  - reachable time:   %s
    ", ra.ReachableTime)
        }
        if ra.RetransmitTimer != 0 {
            writef(&s, "  - retransmit timer: %s
    ", ra.RetransmitTimer)
        }
    
        _, _ = s.WriteString(optionsString(ra.Options))
    
        ll.Print(s.String())
    }
    
    func writef(sw io.StringWriter, format string, a ...interface{}) {
        _, _ = sw.WriteString(fmt.Sprintf(format, a...))
    }
    
    func optStr(o ndp.Option) string {
        switch o := o.(type) {
        case *ndp.LinkLayerAddress:
            dir := "source"
            if o.Direction == ndp.Target {
                dir = "target"
            }
    
            return fmt.Sprintf("%s link-layer address: %s", dir, o.Addr.String())
        case *ndp.MTU:
            return fmt.Sprintf("MTU: %d", *o)
        case *ndp.PrefixInformation:
            var flags []string
            if o.OnLink {
                flags = append(flags, "on-link")
            }
            if o.AutonomousAddressConfiguration {
                flags = append(flags, "autonomous")
            }
    
            return fmt.Sprintf("prefix information: %s/%d, flags: [%s], valid: %s, preferred: %s",
                o.Prefix.String(),
                o.PrefixLength,
                strings.Join(flags, ", "),
                o.ValidLifetime,
                o.PreferredLifetime,
            )
        case *ndp.RawOption:
            return fmt.Sprintf("type: %03d, value: %v", o.Type, o.Value)
        case *ndp.RouteInformation:
            return fmt.Sprintf("route information: %s/%d, preference: %s, lifetime: %s",
                o.Prefix.String(),
                o.PrefixLength,
                o.Preference.String(),
                o.RouteLifetime,
            )
        case *ndp.RecursiveDNSServer:
            var ss []string
            for _, s := range o.Servers {
                ss = append(ss, s.String())
            }
            servers := strings.Join(ss, ", ")
    
            return fmt.Sprintf("recursive DNS servers: lifetime: %s, servers: %s", o.Lifetime, servers)
        case *ndp.DNSSearchList:
            return fmt.Sprintf("DNS search list: lifetime: %s, domain names: %s", o.Lifetime, strings.Join(o.DomainNames, ", "))
        case *ndp.CaptivePortal:
            return fmt.Sprintf("captive portal: %s", *o)
        default:
            panic(fmt.Sprintf("unrecognized option: %v", o))
        }
    }
    
    func optionsString(options []ndp.Option) string {
        if len(options) == 0 {
            return ""
        }
    
        var s strings.Builder
        s.WriteString("  - options:
    ")
    
        for _, o := range options {
            writef(&s, "    - %s
    ", optStr(o))
        }
    
        return s.String()
    }

    测试结果:

    [root@junqiang ndp]# ./ra -i eth0 
    ndp ra> router advertisement from: :::
      - hop limit:        64
      - preference:       Medium
      - router lifetime:  30s
      - options:
        - prefix information: <nil>/64, flags: [autonomous], valid: 1m0s, preferred: 30s
        - source link-layer address: 02:42:ac:11:00:02
    ndp ra> router advertisement from: :::
      - hop limit:        64
      - preference:       Medium
      - router lifetime:  30s
      - options:
        - prefix information: <nil>/64, flags: [autonomous], valid: 1m0s, preferred: 30s
        - source link-layer address: 02:42:ac:11:00:02

    抓包:

    [root@localhost ~]# tcpdump -nn -i eth0 icmp6 -e        
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
    14:22:43.860802 02:42:ac:11:00:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 110: fe80::42:acff:fe11:2 > ff02::1: ICMP6, router advertisement, length 56
    14:22:44.865244 02:42:ac:11:00:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 110: fe80::42:acff:fe11:2 > ff02::1: ICMP6, router advertisement, length 56
    14:22:45.868317 02:42:ac:11:00:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 110: fe80::42:acff:fe11:2 > ff02::1: ICMP6, router advertisement, length 56
    14:22:46.874265 02:42:ac:11:00:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 110: fe80::42:acff:fe11:2 > ff02::1: ICMP6, router advertisement, length 56
  • 相关阅读:
    Head First Java pdf下载
    【ARC068F】Solitaire(dp,计数,思维)
    【BZOJ3270】博物馆(概率dp,高斯消元)
    【BZOJ3143】【HNOI2013】游走(期望dp,高斯消元)
    【BZOJ3622】已经没什么好害怕的了(dp,容斥原理,二项式反演)
    【BJWC2018】上学路线(dp,Lucas,crt)
    【BZOJ4987】Tree(树形dp)
    【SDOI201】黑白棋 /【XSY3064】小奇的博弈(博弈,nim,dp,组合数)
    【HNOI2017】礼物(FFT)
    【BZOJ2502】清理雪道(最大费用最大流)
  • 原文地址:https://www.cnblogs.com/wangjq19920210/p/15074903.html
Copyright © 2011-2022 走看看