func csum(b []byte) uint16 { // Make checksum csumcv := len(b) - 1 // checksum coverage s := uint32(0) for i := 0; i < csumcv; i += 2 { s += uint32(b[i+1])<<8 | uint32(b[i]) } if csumcv&1 == 0 { s += uint32(b[csumcv]) } s = s>>16 + s&0xffff s = s + s>>16 return netu.Htons(^uint16(s)) }
func main() { // Get app params from console args var err error Params, err = NewAppParams(os.Args[1:]) if err != nil { fmt.Fprintln(os.Stderr, err.Error()) return } // seed pseudo random generator; We'll need it later rand.Seed(time.Now().UnixNano()) // Overwrite local only because my network is a bitch if localAddr := os.Getenv("GRNVS_TRACE6_LADDR"); localAddr != "" { fmt.Fprintf(os.Stderr, "Using %s as local ip address\n", localAddr) Params.LocalAddress, err = net.ResolveIPAddr("ip6", localAddr) if err != nil { panic(err) } } // Init raw socket for writing (IPPROTO_RAW is only for writing -> man 7 raw) connWrite = createConn(syscall.AF_INET6, syscall.IPPROTO_RAW) defer connWrite.Close() // Socket for reading sockRead, err = syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, int(netu.Htons(syscall.ETH_P_IPV6))) if err != nil { panic(err) } fileRead = os.NewFile(uintptr(sockRead), fmt.Sprintf("fd-sock-read-%d", sockRead)) defer syscall.Close(sockRead) defer fileRead.Close() // Create the base package, IPv6-Header + ICMP6 Echo Request // Generate id for icmp package id := uint16(rand.Uint32()) pck, l := icmp6.NewEchoRequest(id, 0) // craft request package req := &request{ Header: ipv6.NewHeader(&Params.LocalAddress.IP, &Params.RemoteAddress.IP), Body: pck, } // set some ipv6 header values req.Header.NextHeader = 0x3a req.Header.PayloadLen = l chanReply = make(chan *response, 1) // Start traceing //done := false seq := uint16(0) var resp *response for i := 1; i <= Params.MaxHops; i++ { // print current hop fmt.Printf("%d", i) // Send a package for each hop for j := 0; j < Params.Attempts; j++ { // get request data p := req.Marshal(i, seq) // Send icmp package connWrite.WriteTo(p, Params.RemoteAddress) // Wait for response resp, err = recvResponse(req, &Params.RemoteAddress.IP) if err != nil { fmt.Printf(err.Error()) return } if resp.Timeout { fmt.Printf(" *") } else if resp.EchoReply || resp.TimeExceeded { fmt.Printf(" %s", resp.Sender.String()) } else if resp.DestinationUnreachable { fmt.Printf(" %s!X", resp.Sender.String()) } // increment sequence seq++ } fmt.Print("\n") // stop if we are done if resp.EchoReply || resp.DestinationUnreachable { os.Exit(1) // Termination } } }