shadow1ng/fscan · error
mcs recvData get data error %v
Error message
mcs recvData get data error %v
What it means
During MCS (T.125 Multipoint Communication Service) data reception, the layer header was parsed but reading the remaining data payload bytes from the stream failed. The MCSCONNECT layer emits this on its 'error' channel instead of returning a Go error, and then aborts processing of that packet. It almost always means the underlying transport died or the stream was truncated mid-packet.
Source
Thrown at libs/grdp/protocol/t125/mcs.go:480
per.ReadEnumerates(r)
size, _ := per.ReadLength(r)
// channel ID doesn't match a requested layer
found := false
channelName := ""
for _, channel := range c.channels {
if channel.ID == channelId {
found = true
channelName = channel.Name
break
}
}
if !found {
glog.Error("mcs receive data for an unconnected layer")
return
}
left, err := core.ReadBytes(int(size), r)
if err != nil {
c.Emit("error", errors.New(fmt.Sprintf("mcs recvData get data error %v", err)))
return
}
glog.Debugf("mcs emit channel<%s>:%v", channelName, left)
c.Emit("sec", channelName, left)
}
func (c *MCSClient) recvChannelJoinConfirm(s []byte) {
glog.Debug("mcs recvChannelJoinConfirm", hex.EncodeToString(s))
r := bytes.NewReader(s)
option, err := core.ReadUInt8(r)
if err != nil {
c.Emit("error", err)
return
}
if !readMCSPDUHeader(option, CHANNEL_JOIN_CONFIRM) {
c.Emit("error", errors.New("NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM"))
returnView on GitHub (pinned to 95cc12e753)
Solutions
- Check the wrapped error (%v) for net.Error / io.EOF to confirm the transport died, then reconnect and redo the whole X224/MCS/SEC handshake.
- Enable glog debug output to see the channel name and confirm where in the session the stream broke.
- Verify there are no intermediate proxies/firewalls with idle timeouts shorter than the RDP session keepalive interval.
- If it reproduces deterministically at handshake time, capture traffic and check whether the server's MCS SD length exceeds what the client negotiated (block size mismatch).
Example fix
// before
c.Emit("error", errors.New(fmt.Sprintf("mcs recvData get data error %v", err)))
return
// after
// treat it as a disconnect signal and reconnect upstream
if errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) {
c.Emit("disconnect", err)
return
}
c.Emit("error", fmt.Errorf("mcs recvData get data error %w", err)) Defensive patterns
Strategy: try-catch
Validate before calling
if conn == nil || conn.RemoteAddr() == nil {
return errors.New("transport not connected before MCS handshake")
} Try / catch
// listen on the 'error' channel and distinguish transport death
c.On("error", func(err error) {
if strings.Contains(err.Error(), "mcs recvData get data error") {
reconnect() // transport-level failure
}
}) Prevention
- Enable RDP-level keepalives to detect dead connections before a mid-packet read fails
- Monitor connection health and reconnect on any MCS 'error' emit
- Avoid proxies with aggressive idle timeouts
When it happens
Trigger: recvData passes the 'found' check (channel layer is connected), then core.ReadBytes(int(size), r) fails because the TCP connection is closed, reset, or returned fewer bytes than the MCS DomainPDU header advertised.
Common situations: Server dropped the RDP connection mid-session; network interruption/NAT timeout while a virtual channel packet is in flight; peer sent a corrupted length field causing the reader to block and then hit a read deadline.
Related errors
- bad BER tags
- invalid expected BER tag
- mcs sendConnectInitial write error %v
- ReadConnectResponse %v
- NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/db96a830962bed0c.
Report an issue: GitHub.