Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dispatcher: debug log unroutable SCMP error packets #4683

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 43 additions & 12 deletions dispatcher/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,13 @@ func (s *Server) processMsgNextHop(
switch s.decoded[len(s.decoded)-1] {
case slayers.LayerTypeSCMP:
// send response to BR
if s.scmpLayer.TypeCode.Type() == slayers.SCMPTypeTracerouteRequest ||
s.scmpLayer.TypeCode.Type() == slayers.SCMPTypeEchoRequest {
switch s.scmpLayer.TypeCode.Type() {
case slayers.SCMPTypeEchoRequest, slayers.SCMPTypeTracerouteRequest:
dstAddrPort = prevHop
} else { // relay to end application
dstAddrPort, err = s.getDstSCMP()
case slayers.SCMPTypeEchoReply, slayers.SCMPTypeTracerouteReply:
dstAddrPort, err = s.getSCMPInfoReplyDst()
if err != nil {
log.Error("Getting destination for SCMP message", "err", err)
log.Error("Getting destination for SCMPInfo reply", "err", err)
return nil, netip.AddrPort{}, nil
}
if dstAddrPort.Addr().Unmap().Compare(underlay.Unmap()) != 0 {
Expand All @@ -212,6 +212,21 @@ func (s *Server) processMsgNextHop(
"UDP/SCION:", dstAddrPort.Addr().Unmap().String())
return nil, netip.AddrPort{}, nil
}
default:
dstAddrPort, err = s.getSCMPErrorDst()
if err != nil {
log.Debug("Getting destination for SCMP message",
"underlay", underlay,
"prev_hop", prevHop,
"err", err)
return nil, netip.AddrPort{}, nil
}
if dstAddrPort.Addr().Unmap().Compare(underlay.Unmap()) != 0 {
log.Debug("UDP/IP addr destination different from UDP/SCION addr",
"UDP/IP:", underlay.Unmap().String(),
"UDP/SCION:", dstAddrPort.Addr().Unmap().String())
return nil, netip.AddrPort{}, nil
}
}
case slayers.LayerTypeSCIONUDP:
dstAddrPort, err = s.getDstSCIONUDP()
Expand Down Expand Up @@ -326,7 +341,7 @@ func (s *Server) reverseSCION() error {
return nil
}

func (s *Server) getDstSCMP() (netip.AddrPort, error) {
func (s *Server) getSCMPInfoReplyDst() (netip.AddrPort, error) {
// Check if its SCMPEcho or SCMPTraceroute reply
if s.scmpLayer.TypeCode.Type() == slayers.SCMPTypeEchoReply {
var scmpEcho slayers.SCMPEcho
Expand All @@ -344,25 +359,36 @@ func (s *Server) getDstSCMP() (netip.AddrPort, error) {
}
return addrPortFromBytes(s.scionLayer.RawDstAddr, scmpTraceroute.Identifier)
}
return netip.AddrPort{}, serrors.New("invalid code path")
}

func (s *Server) getSCMPErrorDst() (netip.AddrPort, error) {
errorType := s.scmpLayer.TypeCode.Type()
// Drop unknown SCMP error messages.
if s.scmpLayer.NextLayerType() == gopacket.LayerTypePayload {
return netip.AddrPort{}, serrors.New("unsupported SCMP error message",
"type", s.scmpLayer.TypeCode.Type())
"error_type", s.scmpLayer.TypeCode.Type())
}
l, err := decodeSCMP(&s.scmpLayer)
if err != nil {
return netip.AddrPort{}, err
}
if len(l) != 2 {
return netip.AddrPort{}, serrors.New("SCMP error message without payload")
return netip.AddrPort{},
serrors.New("SCMP error message without payload", "error_type", errorType)
}
gpkt := gopacket.NewPacket(*l[1].(*gopacket.Payload), slayers.LayerTypeSCION,
gopacket.DecodeOptions{
NoCopy: true,
},
)

// For debugging print 200 bytes of the quoted payload.
var payloadForDebug []byte
if log.Root().Enabled(log.DebugLevel) {
payloadForDebug = l[1].(*gopacket.Payload).LayerContents()
payloadForDebug = payloadForDebug[:min(len(payloadForDebug), 200)]
}
// If the offending packet was UDP/SCION, use the source port to deliver.
if udp := gpkt.Layer(slayers.LayerTypeSCIONUDP); udp != nil {
port := udp.(*slayers.UDP).SrcPort
Expand All @@ -371,7 +397,9 @@ func (s *Server) getDstSCMP() (netip.AddrPort, error) {
// they set the source port to 0. But there is no harm, since those
// packets are destined to be dropped anyway.
if port == 0 {
return netip.AddrPort{}, serrors.New("SCMP error with truncated UDP header")
return netip.AddrPort{},
serrors.New("SCMP error with truncated UDP header",
"error_type", errorType, "payload", payloadForDebug)
}
return addrPortFromBytes(s.scionLayer.RawDstAddr, port)
}
Expand All @@ -385,12 +413,14 @@ func (s *Server) getDstSCMP() (netip.AddrPort, error) {
if !tc.InfoMsg() {
return netip.AddrPort{},
serrors.New("SCMP error message in response to SCMP error message",
"type", tc.Type())
"error_type", errorType, "quote_type", tc.Type(), "payload", payloadForDebug)
}
// We only support echo and traceroute requests.
t := tc.Type()
if t != slayers.SCMPTypeEchoRequest && t != slayers.SCMPTypeTracerouteRequest {
return netip.AddrPort{}, serrors.New("unsupported SCMP info message", "type", t)
return netip.AddrPort{},
serrors.New("SCMP error contains unsupported SCMP info message",
"error_type", errorType, "quote_type", t, "payload", payloadForDebug)
}

var port uint16
Expand All @@ -400,7 +430,8 @@ func (s *Server) getDstSCMP() (netip.AddrPort, error) {
} else if tr := gpkt.Layer(slayers.LayerTypeSCMPTraceroute); tr != nil {
port = tr.(*slayers.SCMPTraceroute).Identifier
} else {
return netip.AddrPort{}, serrors.New("SCMP error with truncated payload")
return netip.AddrPort{}, serrors.New("SCMP error with truncated payload",
"error_type", errorType, "payload", payloadForDebug)
}
return addrPortFromBytes(s.scionLayer.RawDstAddr, port)
}
Expand Down
Loading