handle_windows_test.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. //go:build windows
  2. package windivert
  3. import (
  4. "encoding/binary"
  5. "testing"
  6. "unsafe"
  7. "github.com/stretchr/testify/require"
  8. )
  9. // CTL_CODE macro from Windows DDK:
  10. //
  11. // (DeviceType<<16) | (Access<<14) | (Function<<2) | Method
  12. func TestCtlCodeMatchesDDK(t *testing.T) {
  13. t.Parallel()
  14. // FILE_DEVICE_NETWORK=0x12, FILE_READ_DATA|FILE_WRITE_DATA=3, METHOD_OUT_DIRECT=2
  15. require.Equal(t, uint32(0x12E486), ctlCode(0x12, 3, 0x921, 2))
  16. // FILE_READ_DATA=1, METHOD_OUT_DIRECT=2
  17. require.Equal(t, uint32(0x12648E), ctlCode(0x12, 1, 0x923, 2))
  18. }
  19. // Baked-in against windivert_device.h @ v2.2.2. A mismatch here means the
  20. // kernel will reject every ioctl with ERROR_INVALID_FUNCTION.
  21. func TestIoctlCodesMatchUpstream(t *testing.T) {
  22. t.Parallel()
  23. require.Equal(t, uint32(0x12E486), ioctlInitialize)
  24. require.Equal(t, uint32(0x12E489), ioctlStartup)
  25. require.Equal(t, uint32(0x12648E), ioctlRecv)
  26. require.Equal(t, uint32(0x12E491), ioctlSend)
  27. }
  28. func TestBuildIoctlInitialize(t *testing.T) {
  29. t.Parallel()
  30. buf := buildIoctlInitialize(LayerNetwork, 100, FlagSendOnly)
  31. require.Equal(t, uint32(LayerNetwork), binary.LittleEndian.Uint32(buf[0:4]))
  32. // Driver expects priority+PriorityHighest(30000) so the range is non-negative.
  33. require.Equal(t, uint32(30100), binary.LittleEndian.Uint32(buf[4:8]))
  34. require.Equal(t, uint64(FlagSendOnly), binary.LittleEndian.Uint64(buf[8:16]))
  35. }
  36. func TestBuildIoctlInitializePriorityRange(t *testing.T) {
  37. t.Parallel()
  38. lowest := buildIoctlInitialize(LayerNetwork, PriorityLowest, 0)
  39. require.Equal(t, uint32(0), binary.LittleEndian.Uint32(lowest[4:8]))
  40. highest := buildIoctlInitialize(LayerNetwork, PriorityHighest, 0)
  41. require.Equal(t, uint32(60000), binary.LittleEndian.Uint32(highest[4:8]))
  42. zero := buildIoctlInitialize(LayerNetwork, 0, 0)
  43. require.Equal(t, uint32(30000), binary.LittleEndian.Uint32(zero[4:8]))
  44. }
  45. func TestBuildIoctlStartup(t *testing.T) {
  46. t.Parallel()
  47. flags := filterFlagOutbound | filterFlagIP
  48. buf := buildIoctlStartup(flags)
  49. require.Equal(t, flags, binary.LittleEndian.Uint64(buf[0:8]))
  50. // The second quad-word is unused for STARTUP.
  51. require.Equal(t, uint64(0), binary.LittleEndian.Uint64(buf[8:16]))
  52. }
  53. func TestBuildIoctlRecvEmbedsAddressPointer(t *testing.T) {
  54. t.Parallel()
  55. addr := &Address{Timestamp: 0xCAFEBABE}
  56. buf := buildIoctlRecv(addr)
  57. require.Equal(t, uint64(uintptr(unsafe.Pointer(addr))),
  58. binary.LittleEndian.Uint64(buf[0:8]))
  59. // RECV does not carry an address length; driver writes full Address back.
  60. require.Equal(t, uint64(0), binary.LittleEndian.Uint64(buf[8:16]))
  61. }
  62. func TestBuildIoctlSendEmbedsAddressPointerAndSize(t *testing.T) {
  63. t.Parallel()
  64. addr := &Address{}
  65. buf := buildIoctlSend(addr)
  66. require.Equal(t, uint64(uintptr(unsafe.Pointer(addr))),
  67. binary.LittleEndian.Uint64(buf[0:8]))
  68. require.Equal(t, uint64(unsafe.Sizeof(Address{})),
  69. binary.LittleEndian.Uint64(buf[8:16]))
  70. require.Equal(t, uint64(80), binary.LittleEndian.Uint64(buf[8:16]))
  71. }
  72. func TestValidateOpenArgsLayer(t *testing.T) {
  73. t.Parallel()
  74. require.NoError(t, validateOpenArgs(LayerNetwork, 0, 0))
  75. require.Error(t, validateOpenArgs(Layer(1), 0, 0))
  76. require.Error(t, validateOpenArgs(Layer(42), 0, 0))
  77. }
  78. func TestValidateOpenArgsPriorityBounds(t *testing.T) {
  79. t.Parallel()
  80. require.NoError(t, validateOpenArgs(LayerNetwork, PriorityHighest, 0))
  81. require.NoError(t, validateOpenArgs(LayerNetwork, PriorityLowest, 0))
  82. require.NoError(t, validateOpenArgs(LayerNetwork, 0, 0))
  83. require.Error(t, validateOpenArgs(LayerNetwork, PriorityHighest+1, 0))
  84. require.Error(t, validateOpenArgs(LayerNetwork, PriorityLowest-1, 0))
  85. }
  86. func TestValidateOpenArgsFlags(t *testing.T) {
  87. t.Parallel()
  88. require.NoError(t, validateOpenArgs(LayerNetwork, 0, 0))
  89. require.NoError(t, validateOpenArgs(LayerNetwork, 0, FlagSendOnly))
  90. require.NoError(t, validateOpenArgs(LayerNetwork, 0, FlagSniff))
  91. // Sniff and send-only describe contradictory handle roles.
  92. require.Error(t, validateOpenArgs(LayerNetwork, 0, FlagSniff|FlagSendOnly))
  93. // Unknown flag bits must be rejected to surface caller mistakes early.
  94. require.Error(t, validateOpenArgs(LayerNetwork, 0, Flag(0x10)))
  95. require.Error(t, validateOpenArgs(LayerNetwork, 0, FlagSendOnly|Flag(0x10)))
  96. }