// ParseMessage parses b as an ICMP message. Proto must be // iana.ProtocolICMP or iana.ProtocolIPv6ICMP. func ParseMessage(proto int, b []byte) (*Message, error) { if len(b) < 4 { return nil, errors.New("message too short") } var err error switch proto { case iana.ProtocolICMP: m := &Message{Type: ipv4.ICMPType(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])} switch m.Type { case ipv4.ICMPTypeEcho, ipv4.ICMPTypeEchoReply: m.Body, err = parseEcho(b[4:]) if err != nil { return nil, err } default: m.Body = &DefaultMessageBody{Data: b[4:]} } return m, nil case iana.ProtocolIPv6ICMP: m := &Message{Type: ipv6.ICMPType(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])} switch m.Type { case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply: m.Body, err = parseEcho(b[4:]) if err != nil { return nil, err } default: m.Body = &DefaultMessageBody{Data: b[4:]} } return m, nil default: return nil, errors.New("unknown protocol") } }
// parseICMPMessage parses b as an ICMP message. func parseICMPMessage(b []byte) (*icmpMessage, error) { msglen := len(b) if msglen < 4 { return nil, errors.New("message too short") } m := &icmpMessage{Type: ipv6.ICMPType(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])} if msglen > 4 { var err error switch m.Type { case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply: m.Body, err = parseICMPEcho(b[4:]) if err != nil { return nil, err } } } return m, nil }
// method handleND parses arbitrary ICMPv6 messages, currently only router solicitations func handleND(src net.Addr, body []byte) { t := ipv6.ICMPType(body[0]) fmt.Printf("%v from %v\n", t, src) switch t { case ipv6.ICMPTypeRouterSolicitation: // parse ND options options, err := parseOptions(body[8:]) if err != nil { fmt.Println(err) } // check if any of the options is a source LLA var lla *NDOptionLLA = nil for _, o := range options { if o == nil { continue } llaopt, ok := (*o).(*NDOptionLLA) if !ok { continue } lla = llaopt if int(lla.OptionType) != 1 { continue } } if lla == nil { fmt.Println("no source LLA option given") return } lladdr := make(net.HardwareAddr, len(lla.Addr)) copy(lladdr, lla.Addr) rschan <- routerSolicitation{src, lladdr} default: return } }
// ParseMessage parses b as an ICMP message. // Proto must be either the ICMPv4 or ICMPv6 protocol number. func ParseMessage(proto int, b []byte) (*Message, error) { if len(b) < 4 { return nil, errMessageTooShort } var err error m := &Message{Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])} switch proto { case iana.ProtocolICMP: m.Type = ipv4.ICMPType(b[0]) case iana.ProtocolIPv6ICMP: m.Type = ipv6.ICMPType(b[0]) default: return nil, syscall.EINVAL } if fn, ok := parseFns[m.Type]; !ok { m.Body, err = parseDefaultMessageBody(b[4:]) } else { m.Body, err = fn(b[4:]) } if err != nil { return nil, err } return m, nil }
func (i *ICMPv6) ICMPType() ipv6.ICMPType { return ipv6.ICMPType(i.Type) }