refactor: mylib 重命名为 libs

更清晰的目录命名,libs/ 存放内嵌的独立协议实现库。
This commit is contained in:
ZacharyZcR
2026-06-01 08:22:13 +08:00
parent 019d13c9d4
commit a02eed0518
30 changed files with 57 additions and 57 deletions
+760
View File
@@ -0,0 +1,760 @@
package pdu
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
"github.com/shadow1ng/fscan/libs/grdp/glog"
"github.com/lunixbochs/struc"
"github.com/shadow1ng/fscan/libs/grdp/core"
"github.com/shadow1ng/fscan/libs/grdp/protocol/t125/gcc"
)
type CapsType uint16
const (
CAPSTYPE_GENERAL CapsType = 0x0001
CAPSTYPE_BITMAP = 0x0002
CAPSTYPE_ORDER = 0x0003
CAPSTYPE_BITMAPCACHE = 0x0004
CAPSTYPE_CONTROL = 0x0005
CAPSTYPE_ACTIVATION = 0x0007
CAPSTYPE_POINTER = 0x0008
CAPSTYPE_SHARE = 0x0009
CAPSTYPE_COLORCACHE = 0x000A
CAPSTYPE_SOUND = 0x000C
CAPSTYPE_INPUT = 0x000D
CAPSTYPE_FONT = 0x000E
CAPSTYPE_BRUSH = 0x000F
CAPSTYPE_GLYPHCACHE = 0x0010
CAPSTYPE_OFFSCREENCACHE = 0x0011
CAPSTYPE_BITMAPCACHE_HOSTSUPPORT = 0x0012
CAPSTYPE_BITMAPCACHE_REV2 = 0x0013
CAPSTYPE_VIRTUALCHANNEL = 0x0014
CAPSTYPE_DRAWNINEGRIDCACHE = 0x0015
CAPSTYPE_DRAWGDIPLUS = 0x0016
CAPSTYPE_RAIL = 0x0017
CAPSTYPE_WINDOW = 0x0018
CAPSETTYPE_COMPDESK = 0x0019
CAPSETTYPE_MULTIFRAGMENTUPDATE = 0x001A
CAPSETTYPE_LARGE_POINTER = 0x001B
CAPSETTYPE_SURFACE_COMMANDS = 0x001C
CAPSETTYPE_BITMAP_CODECS = 0x001D
CAPSSETTYPE_FRAME_ACKNOWLEDGE = 0x001E
)
func (c CapsType) String() string {
switch c {
case CAPSTYPE_GENERAL:
return "CAPSTYPE_GENERAL"
case CAPSTYPE_BITMAP:
return "CAPSTYPE_BITMAP"
case CAPSTYPE_ORDER:
return "CAPSTYPE_ORDER"
case CAPSTYPE_BITMAPCACHE:
return "CAPSTYPE_BITMAPCACHE"
case CAPSTYPE_CONTROL:
return "CAPSTYPE_CONTROL"
case CAPSTYPE_ACTIVATION:
return "CAPSTYPE_ACTIVATION"
case CAPSTYPE_POINTER:
return "CAPSTYPE_POINTER"
case CAPSTYPE_SHARE:
return "CAPSTYPE_SHARE"
case CAPSTYPE_COLORCACHE:
return "CAPSTYPE_COLORCACHE"
case CAPSTYPE_SOUND:
return "CAPSTYPE_SOUND"
case CAPSTYPE_INPUT:
return "CAPSTYPE_INPUT"
case CAPSTYPE_FONT:
return "CAPSTYPE_FONT"
case CAPSTYPE_BRUSH:
return "CAPSTYPE_BRUSH"
case CAPSTYPE_GLYPHCACHE:
return "CAPSTYPE_GLYPHCACHE"
case CAPSTYPE_OFFSCREENCACHE:
return "CAPSTYPE_OFFSCREENCACHE"
case CAPSTYPE_BITMAPCACHE_HOSTSUPPORT:
return "CAPSTYPE_BITMAPCACHE_HOSTSUPPORT"
case CAPSTYPE_BITMAPCACHE_REV2:
return "CAPSTYPE_BITMAPCACHE_REV2"
case CAPSTYPE_VIRTUALCHANNEL:
return "CAPSTYPE_VIRTUALCHANNEL"
case CAPSTYPE_DRAWNINEGRIDCACHE:
return "CAPSTYPE_DRAWNINEGRIDCACHE"
case CAPSTYPE_DRAWGDIPLUS:
return "CAPSTYPE_DRAWGDIPLUS"
case CAPSTYPE_RAIL:
return "CAPSTYPE_RAIL"
case CAPSTYPE_WINDOW:
return "CAPSTYPE_WINDOW"
case CAPSETTYPE_COMPDESK:
return "CAPSETTYPE_COMPDESK"
case CAPSETTYPE_MULTIFRAGMENTUPDATE:
return "CAPSETTYPE_MULTIFRAGMENTUPDATE"
case CAPSETTYPE_LARGE_POINTER:
return "CAPSETTYPE_LARGE_POINTER"
case CAPSETTYPE_SURFACE_COMMANDS:
return "CAPSETTYPE_SURFACE_COMMANDS"
case CAPSETTYPE_BITMAP_CODECS:
return "CAPSETTYPE_BITMAP_CODECS"
case CAPSSETTYPE_FRAME_ACKNOWLEDGE:
return "CAPSSETTYPE_FRAME_ACKNOWLEDGE"
}
return "Unknown"
}
type MajorType uint16
const (
OSMAJORTYPE_UNSPECIFIED MajorType = 0x0000
OSMAJORTYPE_WINDOWS = 0x0001
OSMAJORTYPE_OS2 = 0x0002
OSMAJORTYPE_MACINTOSH = 0x0003
OSMAJORTYPE_UNIX = 0x0004
OSMAJORTYPE_IOS = 0x0005
OSMAJORTYPE_OSX = 0x0006
OSMAJORTYPE_ANDROID = 0x0007
)
type MinorType uint16
const (
OSMINORTYPE_UNSPECIFIED MinorType = 0x0000
OSMINORTYPE_WINDOWS_31X = 0x0001
OSMINORTYPE_WINDOWS_95 = 0x0002
OSMINORTYPE_WINDOWS_NT = 0x0003
OSMINORTYPE_OS2_V21 = 0x0004
OSMINORTYPE_POWER_PC = 0x0005
OSMINORTYPE_MACINTOSH = 0x0006
OSMINORTYPE_NATIVE_XSERVER = 0x0007
OSMINORTYPE_PSEUDO_XSERVER = 0x0008
OSMINORTYPE_WINDOWS_RT = 0x0009
)
const (
FASTPATH_OUTPUT_SUPPORTED uint16 = 0x0001
NO_BITMAP_COMPRESSION_HDR = 0x0400
LONG_CREDENTIALS_SUPPORTED = 0x0004
AUTORECONNECT_SUPPORTED = 0x0008
ENC_SALTED_CHECKSUM = 0x0010
)
type OrderFlag uint16
const (
NEGOTIATEORDERSUPPORT OrderFlag = 0x0002
ZEROBOUNDSDELTASSUPPORT = 0x0008
COLORINDEXSUPPORT = 0x0020
SOLIDPATTERNBRUSHONLY = 0x0040
ORDERFLAGS_EXTRA_FLAGS = 0x0080
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
*/
type Order uint8
const (
TS_NEG_DSTBLT_INDEX Order = 0x00
TS_NEG_PATBLT_INDEX = 0x01
TS_NEG_SCRBLT_INDEX = 0x02
TS_NEG_MEMBLT_INDEX = 0x03
TS_NEG_MEM3BLT_INDEX = 0x04
TS_NEG_DRAWNINEGRID_INDEX = 0x07
TS_NEG_LINETO_INDEX = 0x08
TS_NEG_MULTI_DRAWNINEGRID_INDEX = 0x09
TS_NEG_SAVEBITMAP_INDEX = 0x0B
TS_NEG_MULTIDSTBLT_INDEX = 0x0F
TS_NEG_MULTIPATBLT_INDEX = 0x10
TS_NEG_MULTISCRBLT_INDEX = 0x11
TS_NEG_MULTIOPAQUERECT_INDEX = 0x12
TS_NEG_FAST_INDEX_INDEX = 0x13
TS_NEG_POLYGON_SC_INDEX = 0x14
TS_NEG_POLYGON_CB_INDEX = 0x15
TS_NEG_POLYLINE_INDEX = 0x16
TS_NEG_FAST_GLYPH_INDEX = 0x18
TS_NEG_ELLIPSE_SC_INDEX = 0x19
TS_NEG_ELLIPSE_CB_INDEX = 0x1A
TS_NEG_GLYPH_INDEX_INDEX = 0x1B
)
type OrderEx uint16
const (
ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT OrderEx = 0x0002
ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT = 0x0004
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
*/
const (
INPUT_FLAG_SCANCODES uint16 = 0x0001
INPUT_FLAG_MOUSEX = 0x0004
INPUT_FLAG_FASTPATH_INPUT = 0x0008
INPUT_FLAG_UNICODE = 0x0010
INPUT_FLAG_FASTPATH_INPUT2 = 0x0020
INPUT_FLAG_UNUSED1 = 0x0040
INPUT_FLAG_UNUSED2 = 0x0080
INPUT_FLAG_MOUSE_HWHEEL = 0x0100
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
*/
type BrushSupport uint32
const (
BRUSH_DEFAULT BrushSupport = 0x00000000
BRUSH_COLOR_8x8 = 0x00000001
BRUSH_COLOR_FULL = 0x00000002
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
*/
type GlyphSupport uint16
const (
GLYPH_SUPPORT_NONE GlyphSupport = 0x0000
GLYPH_SUPPORT_PARTIAL = 0x0001
GLYPH_SUPPORT_FULL = 0x0002
GLYPH_SUPPORT_ENCODE = 0x0003
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
*/
type OffscreenSupportLevel uint32
const (
OSL_FALSE OffscreenSupportLevel = 0x00000000
OSL_TRUE = 0x00000001
)
/**
* @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
*/
type VirtualChannelCompressionFlag uint32
const (
VCCAPS_NO_COMPR VirtualChannelCompressionFlag = 0x00000000
VCCAPS_COMPR_SC = 0x00000001
VCCAPS_COMPR_CS_8K = 0x00000002
)
type SoundFlag uint16
const (
SOUND_NONE SoundFlag = 0x0000
SOUND_BEEPS_FLAG = 0x0001
)
type RailsupportLevel uint32
const (
RAIL_LEVEL_SUPPORTED = 0x00000001
RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED = 0x00000002
RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED = 0x00000004
RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED = 0x00000008
RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED = 0x00000010
RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED = 0x00000020
RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED = 0x00000040
RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED = 0x00000080
)
const (
INPUT_EVENT_SYNC = 0x0000
INPUT_EVENT_UNUSED = 0x0002
INPUT_EVENT_SCANCODE = 0x0004
INPUT_EVENT_UNICODE = 0x0005
INPUT_EVENT_MOUSE = 0x8001
INPUT_EVENT_MOUSEX = 0x8002
)
const (
PTRFLAGS_HWHEEL = 0x0400
PTRFLAGS_WHEEL = 0x0200
PTRFLAGS_WHEEL_NEGATIVE = 0x0100
WheelRotationMask = 0x01FF
PTRFLAGS_MOVE = 0x0800
PTRFLAGS_DOWN = 0x8000
PTRFLAGS_BUTTON1 = 0x1000
PTRFLAGS_BUTTON2 = 0x2000
PTRFLAGS_BUTTON3 = 0x4000
)
const (
KBDFLAGS_EXTENDED = 0x0100
KBDFLAGS_DOWN = 0x4000
KBDFLAGS_RELEASE = 0x8000
)
type SurfaceCmdFlags uint32
const (
SURFCMDS_SET_SURFACE_BITS = 0x00000002
SURFCMDS_FRAME_MARKER = 0x00000010
SURFCMDS_STREAM_SURFACE_BITS = 0x00000040
)
type Capability interface {
Type() CapsType
}
type GeneralCapability struct {
// 010018000100030000020000000015040000000000000000
OSMajorType MajorType `struc:"little"`
OSMinorType MinorType `struc:"little"`
ProtocolVersion uint16 `struc:"little"`
Pad2octetsA uint16 `struc:"little"`
GeneralCompressionTypes uint16 `struc:"little"`
ExtraFlags uint16 `struc:"little"`
UpdateCapabilityFlag uint16 `struc:"little"`
RemoteUnshareFlag uint16 `struc:"little"`
GeneralCompressionLevel uint16 `struc:"little"`
RefreshRectSupport uint8 `struc:"little"`
SuppressOutputSupport uint8 `struc:"little"`
}
func (*GeneralCapability) Type() CapsType {
return CAPSTYPE_GENERAL
}
type BitmapCapability struct {
// 02001c00180001000100010000052003000000000100000001000000
PreferredBitsPerPixel gcc.HighColor `struc:"little"`
Receive1BitPerPixel uint16 `struc:"little"`
Receive4BitsPerPixel uint16 `struc:"little"`
Receive8BitsPerPixel uint16 `struc:"little"`
DesktopWidth uint16 `struc:"little"`
DesktopHeight uint16 `struc:"little"`
Pad2octets uint16 `struc:"little"`
DesktopResizeFlag uint16 `struc:"little"`
BitmapCompressionFlag uint16 `struc:"little"`
HighColorFlags uint8 `struc:"little"`
DrawingFlags uint8 `struc:"little"`
MultipleRectangleSupport uint16 `struc:"little"`
Pad2octetsB uint16 `struc:"little"`
}
func (*BitmapCapability) Type() CapsType {
return CAPSTYPE_BITMAP
}
type BitmapCacheCapability struct {
// 04002800000000000000000000000000000000000000000000000000000000000000000000000000
Pad1 uint32 `struc:"little"`
Pad2 uint32 `struc:"little"`
Pad3 uint32 `struc:"little"`
Pad4 uint32 `struc:"little"`
Pad5 uint32 `struc:"little"`
Pad6 uint32 `struc:"little"`
Cache0Entries uint16 `struc:"little"`
Cache0MaximumCellSize uint16 `struc:"little"`
Cache1Entries uint16 `struc:"little"`
Cache1MaximumCellSize uint16 `struc:"little"`
Cache2Entries uint16 `struc:"little"`
Cache2MaximumCellSize uint16 `struc:"little"`
}
func (*BitmapCacheCapability) Type() CapsType {
return CAPSTYPE_BITMAPCACHE
}
type OrderCapability struct {
// 030058000000000000000000000000000000000000000000010014000000010000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000008403000000000000000000
TerminalDescriptor [16]byte
Pad4octetsA uint32 `struc:"little"`
DesktopSaveXGranularity uint16 `struc:"little"`
DesktopSaveYGranularity uint16 `struc:"little"`
Pad2octetsA uint16 `struc:"little"`
MaximumOrderLevel uint16 `struc:"little"`
NumberFonts uint16 `struc:"little"`
OrderFlags OrderFlag `struc:"little"`
OrderSupport [32]byte
TextFlags uint16 `struc:"little"`
OrderSupportExFlags uint16 `struc:"little"`
Pad4octetsB uint32 `struc:"little"`
DesktopSaveSize uint32 `struc:"little"`
Pad2octetsC uint16 `struc:"little"`
Pad2octetsD uint16 `struc:"little"`
TextANSICodePage uint16 `struc:"little"`
Pad2octetsE uint16 `struc:"little"`
}
func (*OrderCapability) Type() CapsType {
return CAPSTYPE_ORDER
}
type PointerCapability struct {
ColorPointerFlag uint16 `struc:"little"`
ColorPointerCacheSize uint16 `struc:"little"`
// old version of rdp doesn't support ...
PointerCacheSize uint16 `struc:"little"` // only server need
}
func (*PointerCapability) Type() CapsType {
return CAPSTYPE_POINTER
}
type InputCapability struct {
// 0d005c001500000009040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000
Flags uint16 `struc:"little"`
Pad2octetsA uint16 `struc:"little"`
// same value as gcc.ClientCoreSettings.kbdLayout
KeyboardLayout gcc.KeyboardLayout `struc:"little"`
// same value as gcc.ClientCoreSettings.keyboardType
KeyboardType uint32 `struc:"little"`
// same value as gcc.ClientCoreSettings.keyboardSubType
KeyboardSubType uint32 `struc:"little"`
// same value as gcc.ClientCoreSettings.keyboardFnKeys
KeyboardFunctionKey uint32 `struc:"little"`
// same value as gcc.ClientCoreSettingrrs.imeFileName
ImeFileName [64]byte
//need add 0c000000 in the end
}
func (*InputCapability) Type() CapsType {
return CAPSTYPE_INPUT
}
type BrushCapability struct {
// 0f00080000000000
SupportLevel BrushSupport `struc:"little"`
}
func (*BrushCapability) Type() CapsType {
return CAPSTYPE_BRUSH
}
type cacheEntry struct {
Entries uint16 `struc:"little"`
MaximumCellSize uint16 `struc:"little"`
}
type GlyphCapability struct {
// 10003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
GlyphCache [10]cacheEntry `struc:"little"`
FragCache uint32 `struc:"little"`
SupportLevel GlyphSupport `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*GlyphCapability) Type() CapsType {
return CAPSTYPE_GLYPHCACHE
}
type OffscreenBitmapCacheCapability struct {
// 11000c000000000000000000
SupportLevel OffscreenSupportLevel `struc:"little"`
CacheSize uint16 `struc:"little"`
CacheEntries uint16 `struc:"little"`
}
func (*OffscreenBitmapCacheCapability) Type() CapsType {
return CAPSTYPE_OFFSCREENCACHE
}
type BitmapCache2Capability struct {
BitmapCachePersist uint16 `struc:"little"`
Pad2octets uint8 `struc:"little"`
CachesNum uint8 `struc:"little"`
BmpC0Cells uint32 `struc:"little"`
BmpC1Cells uint32 `struc:"little"`
BmpC2Cells uint32 `struc:"little"`
BmpC3Cells uint32 `struc:"little"`
BmpC4Cells uint32 `struc:"little"`
Pad2octets1 [12]byte `struc:"little"`
}
func (*BitmapCache2Capability) Type() CapsType {
return CAPSTYPE_BITMAPCACHE_REV2
}
type VirtualChannelCapability struct {
// 14000c000000000000000000
Flags VirtualChannelCompressionFlag `struc:"little"`
VCChunkSize uint32 `struc:"little"` // optional
}
func (*VirtualChannelCapability) Type() CapsType {
return CAPSTYPE_VIRTUALCHANNEL
}
type SoundCapability struct {
// 0c00080000000000
Flags SoundFlag `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*SoundCapability) Type() CapsType {
return CAPSTYPE_SOUND
}
type ControlCapability struct {
ControlFlags uint16 `struc:"little"`
RemoteDetachFlag uint16 `struc:"little"`
ControlInterest uint16 `struc:"little"`
DetachInterest uint16 `struc:"little"`
}
func (*ControlCapability) Type() CapsType {
return CAPSTYPE_CONTROL
}
type WindowActivationCapability struct {
HelpKeyFlag uint16 `struc:"little"`
HelpKeyIndexFlag uint16 `struc:"little"`
HelpExtendedKeyFlag uint16 `struc:"little"`
WindowManagerKeyFlag uint16 `struc:"little"`
}
func (*WindowActivationCapability) Type() CapsType {
return CAPSTYPE_ACTIVATION
}
type FontCapability struct {
SupportFlags uint16 `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*FontCapability) Type() CapsType {
return CAPSTYPE_FONT
}
type ColorCacheCapability struct {
CacheSize uint16 `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*ColorCacheCapability) Type() CapsType {
return CAPSTYPE_COLORCACHE
}
type ShareCapability struct {
NodeId uint16 `struc:"little"`
Pad2octets uint16 `struc:"little"`
}
func (*ShareCapability) Type() CapsType {
return CAPSTYPE_SHARE
}
type MultiFragmentUpdate struct {
// 1a00080000000000
MaxRequestSize uint32 `struc:"little"`
}
func (*MultiFragmentUpdate) Type() CapsType {
return CAPSETTYPE_MULTIFRAGMENTUPDATE
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegdi/52635737-d144-4f47-9c88-b48ceaf3efb4
type DrawGDIPlusCapability struct {
SupportLevel uint32
GdipVersion uint32
CacheLevel uint32
GdipCacheEntries [10]byte
GdipCacheChunkSize [8]byte
GdipImageCacheProperties [6]byte
}
func (*DrawGDIPlusCapability) Type() CapsType {
return CAPSTYPE_DRAWGDIPLUS
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/86507fed-a0ee-4242-b802-237534a8f65e
type BitmapCodec struct {
GUID [16]byte
ID uint8
PropertiesLength uint16 `struc:"little,sizeof=Properties"`
Properties []byte
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/408b1878-9f6e-4106-8329-1af42219ba6a
type BitmapCodecS struct {
Count uint8 `struc:"sizeof=Array"`
Array []BitmapCodec
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/17e80f50-d163-49de-a23b-fd6456aa472f
type BitmapCodecsCapability struct {
SupportedBitmapCodecs BitmapCodecS // A variable-length field containing a TS_BITMAPCODECS structure (section 2.2.7.2.10.1).
}
func (*BitmapCodecsCapability) Type() CapsType {
return CAPSETTYPE_BITMAP_CODECS
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/fc05c385-46c3-42cb-9ed2-c475a3990e0b
type BitmapCacheHostSupportCapability struct {
CacheVersion uint8
Pad1 uint8
Pad2 uint16
}
func (*BitmapCacheHostSupportCapability) Type() CapsType {
return CAPSTYPE_BITMAPCACHE_HOSTSUPPORT
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/41323437-c753-460e-8108-495a6fdd68a8
type LargePointerCapability struct {
SupportFlags uint16 `struc:"little"`
}
func (*LargePointerCapability) Type() CapsType {
return CAPSETTYPE_LARGE_POINTER
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdperp/36a25e21-25e1-4954-aae8-09aaf6715c79
type RemoteProgramsCapability struct {
RailSupportLevel uint32 `struc:"little"`
}
func (*RemoteProgramsCapability) Type() CapsType {
return CAPSTYPE_RAIL
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdperp/82ec7a69-f7e3-4294-830d-666178b35d15
type WindowListCapability struct {
WndSupportLevel uint32 `struc:"little"`
NumIconCaches uint8
NumIconCacheEntries uint16 `struc:"little"`
}
func (*WindowListCapability) Type() CapsType {
return CAPSTYPE_WINDOW
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/9132002f-f133-4a0f-ba2f-2dc48f1e7f93
type DesktopCompositionCapability struct {
CompDeskSupportLevel uint16 `struc:"little"`
}
func (*DesktopCompositionCapability) Type() CapsType {
return CAPSETTYPE_COMPDESK
}
// see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/aa953018-c0a8-4761-bb12-86586c2cd56a
type SurfaceCommandsCapability struct {
CmdFlags uint32 `struc:"little"`
Reserved uint32 `struc:"little"`
}
func (*SurfaceCommandsCapability) Type() CapsType {
return CAPSETTYPE_SURFACE_COMMANDS
}
type FrameAcknowledgeCapability struct {
FrameCount uint32 `struc:"little"`
}
func (*FrameAcknowledgeCapability) Type() CapsType {
return CAPSSETTYPE_FRAME_ACKNOWLEDGE
}
type DrawNineGridCapability struct {
SupportLevel uint32 `struc:"little"`
CacheSize uint16 `struc:"little"`
CacheEntries uint16 `struc:"little"`
}
func (*DrawNineGridCapability) Type() CapsType {
return CAPSTYPE_DRAWNINEGRIDCACHE
}
func readCapability(r io.Reader) (Capability, error) {
capType, err := core.ReadUint16LE(r)
if err != nil {
return nil, err
}
capLen, err := core.ReadUint16LE(r)
if err != nil {
return nil, err
}
if int(capLen)-4 <= 0 {
return nil, errors.New(fmt.Sprintf("Capability length expected %d", capLen))
}
capBytes, err := core.ReadBytes(int(capLen)-4, r)
if err != nil {
return nil, err
}
capReader := bytes.NewReader(capBytes)
var c Capability
glog.Debugf("Capability type 0x%04x", capType)
switch CapsType(capType) {
case CAPSTYPE_GENERAL:
c = &GeneralCapability{}
case CAPSTYPE_BITMAP:
c = &BitmapCapability{}
case CAPSTYPE_ORDER:
c = &OrderCapability{}
case CAPSTYPE_BITMAPCACHE:
c = &BitmapCacheCapability{}
case CAPSTYPE_POINTER:
c = &PointerCapability{}
case CAPSTYPE_INPUT:
c = &InputCapability{}
case CAPSTYPE_BRUSH:
c = &BrushCapability{}
case CAPSTYPE_GLYPHCACHE:
c = &GlyphCapability{}
case CAPSTYPE_OFFSCREENCACHE:
c = &OffscreenBitmapCacheCapability{}
case CAPSTYPE_VIRTUALCHANNEL:
c = &VirtualChannelCapability{}
case CAPSTYPE_SOUND:
c = &SoundCapability{}
case CAPSTYPE_CONTROL:
c = &ControlCapability{}
case CAPSTYPE_ACTIVATION:
c = &WindowActivationCapability{}
case CAPSTYPE_FONT:
c = &FontCapability{}
case CAPSTYPE_COLORCACHE:
c = &ColorCacheCapability{}
case CAPSTYPE_SHARE:
c = &ShareCapability{}
case CAPSETTYPE_MULTIFRAGMENTUPDATE:
c = &MultiFragmentUpdate{}
case CAPSTYPE_DRAWGDIPLUS:
c = &DrawGDIPlusCapability{}
case CAPSETTYPE_BITMAP_CODECS:
c = &BitmapCodecsCapability{}
case CAPSTYPE_BITMAPCACHE_HOSTSUPPORT:
c = &BitmapCacheHostSupportCapability{}
case CAPSETTYPE_LARGE_POINTER:
c = &LargePointerCapability{}
case CAPSTYPE_RAIL:
c = &RemoteProgramsCapability{}
case CAPSTYPE_WINDOW:
c = &WindowListCapability{}
case CAPSETTYPE_COMPDESK:
c = &DesktopCompositionCapability{}
case CAPSETTYPE_SURFACE_COMMANDS:
c = &SurfaceCommandsCapability{}
case CAPSSETTYPE_FRAME_ACKNOWLEDGE:
c = &FrameAcknowledgeCapability{}
default:
err := errors.New(fmt.Sprintf("unsupported Capability type 0x%04x", capType))
glog.Error(err)
return nil, err
}
if err := struc.Unpack(capReader, c); err != nil {
glog.Error("Capability unpack error", err, fmt.Sprintf("0x%04x", capType), hex.EncodeToString(capBytes))
return nil, err
}
glog.Debugf("Capability<%s>: %+v", c.Type(), c)
return c, nil
}
File diff suppressed because it is too large Load Diff
+465
View File
@@ -0,0 +1,465 @@
package pdu
import (
"bytes"
"encoding/hex"
"github.com/shadow1ng/fscan/libs/grdp/core"
"github.com/shadow1ng/fscan/libs/grdp/emission"
"github.com/shadow1ng/fscan/libs/grdp/glog"
"github.com/shadow1ng/fscan/libs/grdp/protocol/t125/gcc"
)
type PDULayer struct {
emission.Emitter
transport core.Transport
sharedId uint32
userId uint16
channelId uint16
serverCapabilities map[CapsType]Capability
clientCapabilities map[CapsType]Capability
fastPathSender core.FastPathSender
demandActivePDU *DemandActivePDU
}
func NewPDULayer(t core.Transport) *PDULayer {
p := &PDULayer{
Emitter: *emission.NewEmitter(),
transport: t,
sharedId: 0x103EA,
serverCapabilities: map[CapsType]Capability{
CAPSTYPE_GENERAL: &GeneralCapability{
ProtocolVersion: 0x0200,
},
CAPSTYPE_BITMAP: &BitmapCapability{
Receive1BitPerPixel: 0x0001,
Receive4BitsPerPixel: 0x0001,
Receive8BitsPerPixel: 0x0001,
BitmapCompressionFlag: 0x0001,
MultipleRectangleSupport: 0x0001,
},
CAPSTYPE_ORDER: &OrderCapability{
DesktopSaveXGranularity: 1,
DesktopSaveYGranularity: 20,
MaximumOrderLevel: 1,
OrderFlags: NEGOTIATEORDERSUPPORT,
DesktopSaveSize: 480 * 480,
},
CAPSTYPE_POINTER: &PointerCapability{ColorPointerCacheSize: 20},
CAPSTYPE_INPUT: &InputCapability{},
CAPSTYPE_VIRTUALCHANNEL: &VirtualChannelCapability{},
CAPSTYPE_FONT: &FontCapability{SupportFlags: 0x0001},
CAPSTYPE_COLORCACHE: &ColorCacheCapability{CacheSize: 0x0006},
CAPSTYPE_SHARE: &ShareCapability{},
},
clientCapabilities: map[CapsType]Capability{
CAPSTYPE_GENERAL: &GeneralCapability{
ProtocolVersion: 0x0200,
},
CAPSTYPE_BITMAP: &BitmapCapability{
Receive1BitPerPixel: 0x0001,
Receive4BitsPerPixel: 0x0001,
Receive8BitsPerPixel: 0x0001,
BitmapCompressionFlag: 0x0001,
MultipleRectangleSupport: 0x0001,
},
CAPSTYPE_ORDER: &OrderCapability{
DesktopSaveXGranularity: 1,
DesktopSaveYGranularity: 20,
MaximumOrderLevel: 1,
OrderFlags: NEGOTIATEORDERSUPPORT,
DesktopSaveSize: 480 * 480,
TextANSICodePage: 0x4e4,
},
CAPSTYPE_CONTROL: &ControlCapability{0, 0, 2, 2},
CAPSTYPE_ACTIVATION: &WindowActivationCapability{},
CAPSTYPE_POINTER: &PointerCapability{1, 20, 20},
CAPSTYPE_SHARE: &ShareCapability{},
CAPSTYPE_COLORCACHE: &ColorCacheCapability{6, 0},
CAPSTYPE_SOUND: &SoundCapability{0x0001, 0},
CAPSTYPE_INPUT: &InputCapability{},
CAPSTYPE_FONT: &FontCapability{0x0001, 0},
CAPSTYPE_BRUSH: &BrushCapability{BRUSH_COLOR_8x8},
CAPSTYPE_GLYPHCACHE: &GlyphCapability{},
CAPSETTYPE_BITMAP_CODECS: &BitmapCodecsCapability{},
CAPSTYPE_BITMAPCACHE_REV2: &BitmapCache2Capability{
BitmapCachePersist: 2,
CachesNum: 5,
BmpC0Cells: 0x258,
BmpC1Cells: 0x258,
BmpC2Cells: 0x800,
BmpC3Cells: 0x1000,
BmpC4Cells: 0x800,
},
CAPSTYPE_VIRTUALCHANNEL: &VirtualChannelCapability{0, 1600},
CAPSETTYPE_MULTIFRAGMENTUPDATE: &MultiFragmentUpdate{65535},
CAPSTYPE_RAIL: &RemoteProgramsCapability{
RailSupportLevel: RAIL_LEVEL_SUPPORTED |
RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED |
RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED |
RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED |
RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED |
RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED |
RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED |
RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED,
},
CAPSETTYPE_LARGE_POINTER: &LargePointerCapability{1},
CAPSETTYPE_SURFACE_COMMANDS: &SurfaceCommandsCapability{
CmdFlags: SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS | SURFCMDS_FRAME_MARKER,
},
CAPSSETTYPE_FRAME_ACKNOWLEDGE: &FrameAcknowledgeCapability{2},
},
}
t.On("close", func() {
p.Emit("close")
}).On("error", func(err error) {
p.Emit("error", err)
})
return p
}
func (p *PDULayer) sendPDU(message PDUMessage) {
pdu := NewPDU(p.userId, message)
p.transport.Write(pdu.serialize())
}
func (p *PDULayer) sendDataPDU(message DataPDUData) {
dataPdu := NewDataPDU(message, p.sharedId)
p.sendPDU(dataPdu)
}
func (p *PDULayer) SetFastPathSender(f core.FastPathSender) {
p.fastPathSender = f
}
type Client struct {
*PDULayer
clientCoreData *gcc.ClientCoreData
buff *bytes.Buffer
}
func NewClient(t core.Transport) *Client {
c := &Client{
PDULayer: NewPDULayer(t),
buff: &bytes.Buffer{},
}
c.transport.Once("connect", c.connect)
return c
}
func (c *Client) connect(data *gcc.ClientCoreData, userId uint16, channelId uint16) {
glog.Debug("pdu connect:", userId, ",", channelId)
c.clientCoreData = data
c.userId = userId
c.channelId = channelId
c.transport.Once("data", c.recvDemandActivePDU)
}
func (c *Client) recvDemandActivePDU(s []byte) {
glog.Trace("PDU recvDemandActivePDU", hex.EncodeToString(s))
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
if pdu.ShareCtrlHeader.PDUType != PDUTYPE_DEMANDACTIVEPDU {
glog.Info("PDU ignore message during connection sequence, type is", pdu.ShareCtrlHeader.PDUType)
c.transport.Once("data", c.recvDemandActivePDU)
return
}
c.sharedId = pdu.Message.(*DemandActivePDU).SharedId
c.demandActivePDU = pdu.Message.(*DemandActivePDU)
for _, caps := range c.demandActivePDU.CapabilitySets {
glog.Debugf("serverCapabilities<%s>: %+v", caps.Type(), caps)
c.serverCapabilities[caps.Type()] = caps
}
c.sendConfirmActivePDU()
c.sendClientFinalizeSynchronizePDU()
c.transport.Once("data", c.recvServerSynchronizePDU)
}
func (c *Client) sendConfirmActivePDU() {
glog.Debug("PDU start sendConfirmActivePDU")
pdu := NewConfirmActivePDU()
generalCapa := c.clientCapabilities[CAPSTYPE_GENERAL].(*GeneralCapability)
generalCapa.OSMajorType = OSMAJORTYPE_WINDOWS
generalCapa.OSMinorType = OSMINORTYPE_WINDOWS_NT
generalCapa.ExtraFlags = LONG_CREDENTIALS_SUPPORTED | NO_BITMAP_COMPRESSION_HDR |
FASTPATH_OUTPUT_SUPPORTED | AUTORECONNECT_SUPPORTED
generalCapa.RefreshRectSupport = 0
generalCapa.SuppressOutputSupport = 0
bitmapCapa := c.clientCapabilities[CAPSTYPE_BITMAP].(*BitmapCapability)
bitmapCapa.PreferredBitsPerPixel = c.clientCoreData.HighColorDepth
bitmapCapa.DesktopWidth = c.clientCoreData.DesktopWidth
bitmapCapa.DesktopHeight = c.clientCoreData.DesktopHeight
bitmapCapa.DesktopResizeFlag = 0x0001
orderCapa := c.clientCapabilities[CAPSTYPE_ORDER].(*OrderCapability)
orderCapa.OrderFlags = NEGOTIATEORDERSUPPORT | ZEROBOUNDSDELTASSUPPORT | COLORINDEXSUPPORT | ORDERFLAGS_EXTRA_FLAGS
orderCapa.OrderSupportExFlags |= ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT
orderCapa.OrderSupport[TS_NEG_DSTBLT_INDEX] = 1
orderCapa.OrderSupport[TS_NEG_PATBLT_INDEX] = 1
orderCapa.OrderSupport[TS_NEG_SCRBLT_INDEX] = 1
//orderCapa.OrderSupport[TS_NEG_LINETO_INDEX] = 1
//orderCapa.OrderSupport[TS_NEG_MEMBLT_INDEX] = 1
//orderCapa.OrderSupport[TS_NEG_MEM3BLT_INDEX] = 1
//orderCapa.OrderSupport[TS_NEG_POLYLINE_INDEX] = 1
/*orderCapa.OrderSupport[TS_NEG_MULTIOPAQUERECT_INDEX] = 1
orderCapa.OrderSupport[TS_NEG_GLYPH_INDEX_INDEX] = 1
//orderCapa.OrderSupport[TS_NEG_DRAWNINEGRID_INDEX] = 1
orderCapa.OrderSupport[TS_NEG_SAVEBITMAP_INDEX] = 1
orderCapa.OrderSupport[TS_NEG_POLYGON_SC_INDEX] = 1
orderCapa.OrderSupport[TS_NEG_POLYGON_CB_INDEX] = 1
orderCapa.OrderSupport[TS_NEG_ELLIPSE_SC_INDEX] = 1
orderCapa.OrderSupport[TS_NEG_ELLIPSE_CB_INDEX] = 1*/
orderCapa.OrderSupport[TS_NEG_FAST_GLYPH_INDEX] = 1
inputCapa := c.clientCapabilities[CAPSTYPE_INPUT].(*InputCapability)
inputCapa.Flags = INPUT_FLAG_SCANCODES | INPUT_FLAG_MOUSEX | INPUT_FLAG_UNICODE
inputCapa.KeyboardLayout = c.clientCoreData.KbdLayout
inputCapa.KeyboardType = c.clientCoreData.KeyboardType
inputCapa.KeyboardSubType = c.clientCoreData.KeyboardSubType
inputCapa.KeyboardFunctionKey = c.clientCoreData.KeyboardFnKeys
inputCapa.ImeFileName = c.clientCoreData.ImeFileName
glyphCapa := c.clientCapabilities[CAPSTYPE_GLYPHCACHE].(*GlyphCapability)
/*glyphCapa.GlyphCache[0] = cacheEntry{254, 4}
glyphCapa.GlyphCache[1] = cacheEntry{254, 4}
glyphCapa.GlyphCache[2] = cacheEntry{254, 8}
glyphCapa.GlyphCache[3] = cacheEntry{254, 8}
glyphCapa.GlyphCache[4] = cacheEntry{254, 16}
glyphCapa.GlyphCache[5] = cacheEntry{254, 32}
glyphCapa.GlyphCache[6] = cacheEntry{254, 64}
glyphCapa.GlyphCache[7] = cacheEntry{254, 128}
glyphCapa.GlyphCache[8] = cacheEntry{254, 256}
glyphCapa.GlyphCache[9] = cacheEntry{64, 2048}
glyphCapa.FragCache = 0x01000100*/
glyphCapa.SupportLevel = GLYPH_SUPPORT_NONE
pdu.SharedId = c.sharedId
for _, v := range c.clientCapabilities {
glog.Debugf("clientCapabilities<%s>: %+v", v.Type(), v)
pdu.CapabilitySets = append(pdu.CapabilitySets, v)
}
pdu.NumberCapabilities = uint16(len(pdu.CapabilitySets))
pdu.LengthSourceDescriptor = c.demandActivePDU.LengthSourceDescriptor
pdu.SourceDescriptor = c.demandActivePDU.SourceDescriptor
pdu.LengthCombinedCapabilities = c.demandActivePDU.LengthCombinedCapabilities
c.sendPDU(pdu)
}
func (c *Client) sendClientFinalizeSynchronizePDU() {
glog.Debug("PDU start sendClientFinalizeSynchronizePDU")
c.sendDataPDU(NewSynchronizeDataPDU(c.channelId))
c.sendDataPDU(&ControlDataPDU{Action: CTRLACTION_COOPERATE})
c.sendDataPDU(&ControlDataPDU{Action: CTRLACTION_REQUEST_CONTROL})
//c.sendDataPDU(&PersistKeyPDU{BBitMask: 0x03})
c.sendDataPDU(&FontListDataPDU{ListFlags: 0x0003, EntrySize: 0x0032})
}
func (c *Client) recvServerSynchronizePDU(s []byte) {
glog.Debug("PDU recvServerSynchronizePDU")
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
dataPdu, ok := pdu.Message.(*DataPDU)
if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_SYNCHRONIZE {
if ok {
glog.Error("recvServerSynchronizePDU ignore datapdu type2", dataPdu.Header.PDUType2)
} else {
glog.Error("recvServerSynchronizePDU ignore message type", pdu.ShareCtrlHeader.PDUType)
}
glog.Infof("%+v", dataPdu)
c.transport.Once("data", c.recvServerSynchronizePDU)
return
}
c.transport.Once("data", c.recvServerControlCooperatePDU)
}
func (c *Client) recvServerControlCooperatePDU(s []byte) {
glog.Debug("PDU recvServerControlCooperatePDU")
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
dataPdu, ok := pdu.Message.(*DataPDU)
if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_CONTROL {
if ok {
glog.Error("recvServerControlCooperatePDU ignore datapdu type2", dataPdu.Header.PDUType2)
} else {
glog.Error("recvServerControlCooperatePDU ignore message type", pdu.ShareCtrlHeader.PDUType)
}
c.transport.Once("data", c.recvServerControlCooperatePDU)
return
}
glog.Debugf("-------------PDUType2 = %02x\n", dataPdu.Header.PDUType2)
if dataPdu.Header.PDUType2 == PDUTYPE2_SAVE_SESSION_INFO {
c.Emit("success")
}
if dataPdu.Data.(*ControlDataPDU).Action != CTRLACTION_COOPERATE {
glog.Error("recvServerControlCooperatePDU ignore action", dataPdu.Data.(*ControlDataPDU).Action)
c.transport.Once("data", c.recvServerControlCooperatePDU)
return
}
c.transport.Once("data", c.recvServerControlGrantedPDU)
}
func (c *Client) recvServerControlGrantedPDU(s []byte) {
glog.Debug("PDU recvServerControlGrantedPDU")
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
dataPdu, ok := pdu.Message.(*DataPDU)
if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_CONTROL {
if ok {
glog.Error("recvServerControlGrantedPDU ignore datapdu type2", dataPdu.Header.PDUType2)
} else {
glog.Error("recvServerControlGrantedPDU ignore message type", pdu.ShareCtrlHeader.PDUType)
}
c.transport.Once("data", c.recvServerControlGrantedPDU)
return
}
if dataPdu.Data.(*ControlDataPDU).Action != CTRLACTION_GRANTED_CONTROL {
glog.Error("recvServerControlGrantedPDU ignore action", dataPdu.Data.(*ControlDataPDU).Action)
c.transport.Once("data", c.recvServerControlGrantedPDU)
return
}
c.transport.Once("data", c.recvServerFontMapPDU)
}
func (c *Client) recvServerFontMapPDU(s []byte) {
glog.Debug("PDU recvServerFontMapPDU")
r := bytes.NewReader(s)
pdu, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
dataPdu, ok := pdu.Message.(*DataPDU)
if !ok || dataPdu.Header.PDUType2 != PDUTYPE2_FONTMAP {
if ok {
glog.Error("recvServerFontMapPDU ignore datapdu type2", dataPdu.Header.PDUType2)
} else {
glog.Error("recvServerFontMapPDU ignore message type", pdu.ShareCtrlHeader.PDUType)
}
return
}
c.transport.On("data", c.recvPDU)
c.Emit("ready")
}
func (c *Client) recvPDU(s []byte) {
glog.Trace("PDU recvPDU", hex.EncodeToString(s))
r := bytes.NewReader(s)
if r.Len() > 0 {
p, err := readPDU(r)
if err != nil {
glog.Error(err)
return
}
if p.ShareCtrlHeader.PDUType == PDUTYPE_DEACTIVATEALLPDU {
c.transport.Once("data", c.recvDemandActivePDU)
} else if p.ShareCtrlHeader.PDUType == PDUTYPE_DATAPDU {
d := p.Message.(*DataPDU)
if d.Header.PDUType2 == PDUTYPE2_UPDATE {
up := d.Data.(*UpdateDataPDU)
p := up.Udata
if up.UpdateType == FASTPATH_UPDATETYPE_BITMAP {
c.Emit("bitmap", p.(*BitmapUpdateDataPDU).Rectangles)
}
}
if d.Header.PDUType2 == PDUTYPE2_SAVE_SESSION_INFO {
c.Emit("success")
}
}
}
}
func (c *Client) RecvFastPath(secFlag byte, s []byte) {
glog.Trace("PDU RecvFastPath", hex.EncodeToString(s))
r := bytes.NewReader(s)
for r.Len() > 0 {
updateHeader, err := core.ReadUInt8(r)
if err != nil {
return
}
updateCode := updateHeader & 0x0f
fragmentation := updateHeader & 0x30
compression := updateHeader & 0xC0
var compressionFlags uint8 = 0
if compression == FASTPATH_OUTPUT_COMPRESSION_USED {
compressionFlags, err = core.ReadUInt8(r)
}
size, err := core.ReadUint16LE(r)
if err != nil {
return
}
glog.Trace("Code:", FastPathUpdateType(updateCode),
"compressionFlags:", compressionFlags,
"fragmentation:", fragmentation,
"size:", size, "len:", r.Len())
if compressionFlags&RDP_MPPC_COMPRESSED != 0 {
glog.Info("RDP_MPPC_COMPRESSED")
}
if fragmentation != FASTPATH_FRAGMENT_SINGLE {
if fragmentation == FASTPATH_FRAGMENT_FIRST {
c.buff.Reset()
}
b, _ := core.ReadBytes(r.Len(), r)
c.buff.Write(b)
if fragmentation != FASTPATH_FRAGMENT_LAST {
return
}
r = bytes.NewReader(c.buff.Bytes())
}
p, err := readFastPathUpdatePDU(r, updateCode)
if err != nil || p == nil || p.Data == nil {
glog.Debug("readFastPathUpdatePDU:", err)
return
}
if updateCode == FASTPATH_UPDATETYPE_BITMAP {
c.Emit("bitmap", p.Data.(*FastPathBitmapUpdateDataPDU).Rectangles)
} else if updateCode == FASTPATH_UPDATETYPE_COLOR {
c.Emit("color", p.Data.(*FastPathColorPdu))
}
}
}
type InputEventsInterface interface {
Serialize() []byte
}
func (c *Client) SendInputEvents(msgType uint16, events []InputEventsInterface) {
p := &ClientInputEventPDU{}
p.NumEvents = uint16(len(events))
p.SlowPathInputEvents = make([]SlowPathInputEvent, 0, p.NumEvents)
for _, in := range events {
seria := in.Serialize()
s := SlowPathInputEvent{0, msgType, len(seria), seria}
p.SlowPathInputEvents = append(p.SlowPathInputEvents, s)
}
c.sendDataPDU(p)
}