瀏覽代碼

icmp: make Marshal of MessageBody, ParseMessage work correctly on parameter problem message

The wire format of parameter problem message is slightly different
between ICMPv4 and ICMPv6. We need to distinguish each message's
protocol family for avoiding dropping wrong wire format stuff on the
wire.

This is an API breaking change.

type MessageBody interface, Marshal() ([]byte, error)

is replaced with

type MessageBody interface, Marshal(int) ([]byte, error)

Fixes #9394.

Change-Id: Id692c76f85a2714dd011342e648b31395ca668bf
Mikio Hara 11 年之前
父節點
當前提交
7ed368b9e7
共有 7 個文件被更改,包括 33 次插入19 次删除
  1. 2 2
      icmp/dstunreach.go
  2. 2 2
      icmp/echo.go
  3. 4 4
      icmp/message.go
  4. 4 3
      icmp/messagebody.go
  5. 2 2
      icmp/packettoobig.go
  6. 17 4
      icmp/paramprob.go
  7. 2 2
      icmp/timeexceeded.go

+ 2 - 2
icmp/dstunreach.go

@@ -19,7 +19,7 @@ func (p *DstUnreach) Len() int {
 }
 }
 
 
 // Marshal implements the Marshal method of MessageBody interface.
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *DstUnreach) Marshal() ([]byte, error) {
+func (p *DstUnreach) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	b := make([]byte, 4+len(p.Data))
 	copy(b[4:], p.Data)
 	copy(b[4:], p.Data)
 	return b, nil
 	return b, nil
@@ -27,7 +27,7 @@ func (p *DstUnreach) Marshal() ([]byte, error) {
 
 
 // parseDstUnreach parses b as an ICMP destination unreachable message
 // parseDstUnreach parses b as an ICMP destination unreachable message
 // body.
 // body.
-func parseDstUnreach(b []byte) (MessageBody, error) {
+func parseDstUnreach(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	bodyLen := len(b)
 	if bodyLen < 4 {
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
 		return nil, errMessageTooShort

+ 2 - 2
icmp/echo.go

@@ -20,7 +20,7 @@ func (p *Echo) Len() int {
 }
 }
 
 
 // Marshal implements the Marshal method of MessageBody interface.
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *Echo) Marshal() ([]byte, error) {
+func (p *Echo) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	b := make([]byte, 4+len(p.Data))
 	b[0], b[1] = byte(p.ID>>8), byte(p.ID)
 	b[0], b[1] = byte(p.ID>>8), byte(p.ID)
 	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
 	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
@@ -29,7 +29,7 @@ func (p *Echo) Marshal() ([]byte, error) {
 }
 }
 
 
 // parseEcho parses b as an ICMP echo request or reply message body.
 // parseEcho parses b as an ICMP echo request or reply message body.
-func parseEcho(b []byte) (MessageBody, error) {
+func parseEcho(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	bodyLen := len(b)
 	if bodyLen < 4 {
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
 		return nil, errMessageTooShort

+ 4 - 4
icmp/message.go

@@ -63,7 +63,7 @@ func (m *Message) Marshal(psh []byte) ([]byte, error) {
 		b = append(psh, b...)
 		b = append(psh, b...)
 	}
 	}
 	if m.Body != nil && m.Body.Len() != 0 {
 	if m.Body != nil && m.Body.Len() != 0 {
-		mb, err := m.Body.Marshal()
+		mb, err := m.Body.Marshal(m.Type.Protocol())
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -93,7 +93,7 @@ func (m *Message) Marshal(psh []byte) ([]byte, error) {
 	return b[len(psh):], nil
 	return b[len(psh):], nil
 }
 }
 
 
-var parseFns = map[Type]func([]byte) (MessageBody, error){
+var parseFns = map[Type]func(int, []byte) (MessageBody, error){
 	ipv4.ICMPTypeDestinationUnreachable: parseDstUnreach,
 	ipv4.ICMPTypeDestinationUnreachable: parseDstUnreach,
 	ipv4.ICMPTypeTimeExceeded:           parseTimeExceeded,
 	ipv4.ICMPTypeTimeExceeded:           parseTimeExceeded,
 	ipv4.ICMPTypeParameterProblem:       parseParamProb,
 	ipv4.ICMPTypeParameterProblem:       parseParamProb,
@@ -127,9 +127,9 @@ func ParseMessage(proto int, b []byte) (*Message, error) {
 		return nil, syscall.EINVAL
 		return nil, syscall.EINVAL
 	}
 	}
 	if fn, ok := parseFns[m.Type]; !ok {
 	if fn, ok := parseFns[m.Type]; !ok {
-		m.Body, err = parseDefaultMessageBody(b[4:])
+		m.Body, err = parseDefaultMessageBody(proto, b[4:])
 	} else {
 	} else {
-		m.Body, err = fn(b[4:])
+		m.Body, err = fn(proto, b[4:])
 	}
 	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err

+ 4 - 3
icmp/messagebody.go

@@ -10,7 +10,8 @@ type MessageBody interface {
 	Len() int
 	Len() int
 
 
 	// Marshal returns the binary enconding of ICMP message body.
 	// Marshal returns the binary enconding of ICMP message body.
-	Marshal() ([]byte, error)
+	// Proto must be either the ICMPv4 or ICMPv6 protocol number.
+	Marshal(proto int) ([]byte, error)
 }
 }
 
 
 // A DefaultMessageBody represents the default message body.
 // A DefaultMessageBody represents the default message body.
@@ -27,12 +28,12 @@ func (p *DefaultMessageBody) Len() int {
 }
 }
 
 
 // Marshal implements the Marshal method of MessageBody interface.
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *DefaultMessageBody) Marshal() ([]byte, error) {
+func (p *DefaultMessageBody) Marshal(proto int) ([]byte, error) {
 	return p.Data, nil
 	return p.Data, nil
 }
 }
 
 
 // parseDefaultMessageBody parses b as an ICMP message body.
 // parseDefaultMessageBody parses b as an ICMP message body.
-func parseDefaultMessageBody(b []byte) (MessageBody, error) {
+func parseDefaultMessageBody(proto int, b []byte) (MessageBody, error) {
 	p := &DefaultMessageBody{Data: make([]byte, len(b))}
 	p := &DefaultMessageBody{Data: make([]byte, len(b))}
 	copy(p.Data, b)
 	copy(p.Data, b)
 	return p, nil
 	return p, nil

+ 2 - 2
icmp/packettoobig.go

@@ -19,7 +19,7 @@ func (p *PacketTooBig) Len() int {
 }
 }
 
 
 // Marshal implements the Marshal method of MessageBody interface.
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *PacketTooBig) Marshal() ([]byte, error) {
+func (p *PacketTooBig) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	b := make([]byte, 4+len(p.Data))
 	b[0], b[1], b[2], b[3] = byte(p.MTU>>24), byte(p.MTU>>16), byte(p.MTU>>8), byte(p.MTU)
 	b[0], b[1], b[2], b[3] = byte(p.MTU>>24), byte(p.MTU>>16), byte(p.MTU>>8), byte(p.MTU)
 	copy(b[4:], p.Data)
 	copy(b[4:], p.Data)
@@ -27,7 +27,7 @@ func (p *PacketTooBig) Marshal() ([]byte, error) {
 }
 }
 
 
 // parsePacketTooBig parses b as an ICMP packet too big message body.
 // parsePacketTooBig parses b as an ICMP packet too big message body.
-func parsePacketTooBig(b []byte) (MessageBody, error) {
+func parsePacketTooBig(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	bodyLen := len(b)
 	if bodyLen < 4 {
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
 		return nil, errMessageTooShort

+ 17 - 4
icmp/paramprob.go

@@ -4,6 +4,8 @@
 
 
 package icmp
 package icmp
 
 
+import "golang.org/x/net/internal/iana"
+
 // A ParamProb represents an ICMP parameter problem message body.
 // A ParamProb represents an ICMP parameter problem message body.
 type ParamProb struct {
 type ParamProb struct {
 	Pointer uintptr // offset within the data where the error was detected
 	Pointer uintptr // offset within the data where the error was detected
@@ -19,20 +21,31 @@ func (p *ParamProb) Len() int {
 }
 }
 
 
 // Marshal implements the Marshal method of MessageBody interface.
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *ParamProb) Marshal() ([]byte, error) {
+func (p *ParamProb) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	b := make([]byte, 4+len(p.Data))
-	b[0], b[1], b[2], b[3] = byte(p.Pointer>>24), byte(p.Pointer>>16), byte(p.Pointer>>8), byte(p.Pointer)
+	switch proto {
+	case iana.ProtocolICMP:
+		b[0] = byte(p.Pointer)
+	case iana.ProtocolIPv6ICMP:
+		b[0], b[1], b[2], b[3] = byte(p.Pointer>>24), byte(p.Pointer>>16), byte(p.Pointer>>8), byte(p.Pointer)
+	}
 	copy(b[4:], p.Data)
 	copy(b[4:], p.Data)
 	return b, nil
 	return b, nil
 }
 }
 
 
 // parseParamProb parses b as an ICMP parameter problem message body.
 // parseParamProb parses b as an ICMP parameter problem message body.
-func parseParamProb(b []byte) (MessageBody, error) {
+func parseParamProb(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	bodyLen := len(b)
 	if bodyLen < 4 {
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
 		return nil, errMessageTooShort
 	}
 	}
-	p := &ParamProb{Pointer: uintptr(b[0])<<24 | uintptr(b[1])<<16 | uintptr(b[2])<<8 | uintptr(b[3])}
+	p := &ParamProb{}
+	switch proto {
+	case iana.ProtocolICMP:
+		p.Pointer = uintptr(b[0])
+	case iana.ProtocolIPv6ICMP:
+		p.Pointer = uintptr(b[0])<<24 | uintptr(b[1])<<16 | uintptr(b[2])<<8 | uintptr(b[3])
+	}
 	if bodyLen > 4 {
 	if bodyLen > 4 {
 		p.Data = make([]byte, bodyLen-4)
 		p.Data = make([]byte, bodyLen-4)
 		copy(p.Data, b[4:])
 		copy(p.Data, b[4:])

+ 2 - 2
icmp/timeexceeded.go

@@ -18,14 +18,14 @@ func (p *TimeExceeded) Len() int {
 }
 }
 
 
 // Marshal implements the Marshal method of MessageBody interface.
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *TimeExceeded) Marshal() ([]byte, error) {
+func (p *TimeExceeded) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	b := make([]byte, 4+len(p.Data))
 	copy(b[4:], p.Data)
 	copy(b[4:], p.Data)
 	return b, nil
 	return b, nil
 }
 }
 
 
 // parseTimeExceeded parses b as an ICMP time exceeded message body.
 // parseTimeExceeded parses b as an ICMP time exceeded message body.
-func parseTimeExceeded(b []byte) (MessageBody, error) {
+func parseTimeExceeded(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	bodyLen := len(b)
 	if bodyLen < 4 {
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
 		return nil, errMessageTooShort