Commit 7ed368b9 authored by Mikio Hara's avatar Mikio Hara

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
parent b1ee7b3f
......@@ -19,7 +19,7 @@ func (p *DstUnreach) Len() int {
}
// 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))
copy(b[4:], p.Data)
return b, nil
......@@ -27,7 +27,7 @@ func (p *DstUnreach) Marshal() ([]byte, error) {
// parseDstUnreach parses b as an ICMP destination unreachable message
// body.
func parseDstUnreach(b []byte) (MessageBody, error) {
func parseDstUnreach(proto int, b []byte) (MessageBody, error) {
bodyLen := len(b)
if bodyLen < 4 {
return nil, errMessageTooShort
......
......@@ -20,7 +20,7 @@ func (p *Echo) Len() int {
}
// 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[0], b[1] = byte(p.ID>>8), byte(p.ID)
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.
func parseEcho(b []byte) (MessageBody, error) {
func parseEcho(proto int, b []byte) (MessageBody, error) {
bodyLen := len(b)
if bodyLen < 4 {
return nil, errMessageTooShort
......
......@@ -63,7 +63,7 @@ func (m *Message) Marshal(psh []byte) ([]byte, error) {
b = append(psh, b...)
}
if m.Body != nil && m.Body.Len() != 0 {
mb, err := m.Body.Marshal()
mb, err := m.Body.Marshal(m.Type.Protocol())
if err != nil {
return nil, err
}
......@@ -93,7 +93,7 @@ func (m *Message) Marshal(psh []byte) ([]byte, error) {
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.ICMPTypeTimeExceeded: parseTimeExceeded,
ipv4.ICMPTypeParameterProblem: parseParamProb,
......@@ -127,9 +127,9 @@ func ParseMessage(proto int, b []byte) (*Message, error) {
return nil, syscall.EINVAL
}
if fn, ok := parseFns[m.Type]; !ok {
m.Body, err = parseDefaultMessageBody(b[4:])
m.Body, err = parseDefaultMessageBody(proto, b[4:])
} else {
m.Body, err = fn(b[4:])
m.Body, err = fn(proto, b[4:])
}
if err != nil {
return nil, err
......
......@@ -10,7 +10,8 @@ type MessageBody interface {
Len() int
// 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.
......@@ -27,12 +28,12 @@ func (p *DefaultMessageBody) Len() int {
}
// 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
}
// 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))}
copy(p.Data, b)
return p, nil
......
......@@ -19,7 +19,7 @@ func (p *PacketTooBig) Len() int {
}
// 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[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)
......@@ -27,7 +27,7 @@ func (p *PacketTooBig) Marshal() ([]byte, error) {
}
// 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)
if bodyLen < 4 {
return nil, errMessageTooShort
......
......@@ -4,6 +4,8 @@
package icmp
import "golang.org/x/net/internal/iana"
// A ParamProb represents an ICMP parameter problem message body.
type ParamProb struct {
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.
func (p *ParamProb) Marshal() ([]byte, error) {
func (p *ParamProb) Marshal(proto int) ([]byte, error) {
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)
return b, nil
}
// 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)
if bodyLen < 4 {
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 {
p.Data = make([]byte, bodyLen-4)
copy(p.Data, b[4:])
......
......@@ -18,14 +18,14 @@ func (p *TimeExceeded) Len() int {
}
// 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))
copy(b[4:], p.Data)
return b, nil
}
// 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)
if bodyLen < 4 {
return nil, errMessageTooShort
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment