Home › Forums › Discussions › Support › I have a problem rewriting NDIS in Go
- This topic has 2 replies, 2 voices, and was last updated 1 hour, 3 minutes ago by devman.
-
AuthorPosts
-
October 24, 2024 at 10:32 am #13903
Hello,
I was trying to rewrite the NDIS API from C++ code to Go and I faced a problem which I tried to fix but because I don’t get any proper error or result I can’t tell what’s exactly wrong.
This is part of the code that is working and showing the result correctly, at least to my udnerstanding:
`
import (
“fmt”
“strings”
“unsafe”“golang.org/x/sys/windows”
)type NdisApi struct {
hFileHandle windows.Handle
}func NewNdisApi() (*NdisApi, error) {
devicePath, err := windows.UTF16PtrFromString(“\\\\.\\NDISRD”)
if err != nil {
return nil, err
}handle, err := windows.CreateFile(
devicePath, // Device path
windows.GENERIC_READ|windows.GENERIC_WRITE,
0,
nil,
windows.OPEN_EXISTING,
windows.FILE_ATTRIBUTE_NORMAL,
0)
if err != nil {
return nil, err
}
return &NdisApi{hFileHandle: handle}, nil
}func (api *NdisApi) DeviceIoControl(dwService uint32, BuffIn unsafe.Pointer, SizeIn uint32, BuffOut unsafe.Pointer, SizeOut uint32, SizeRet *uint32, povlp *windows.Overlapped) error {
var returnedBytes uint32
if SizeRet == nil {
SizeRet = &returnedBytes
}return windows.DeviceIoControl(
api.hFileHandle,
dwService,
(*byte)(BuffIn),
SizeIn,
(*byte)(BuffOut),
SizeOut,
SizeRet,
povlp)
}// GetVersion Retrieves the NDISAPI driver version.
func (api *NdisApi) GetVersion() (*uint64, error) {
var nDriverAPIVersion uint64err := api.DeviceIoControl(
IOCTL_NDISRD_GET_VERSION,
unsafe.Pointer(&nDriverAPIVersion),
uint32(unsafe.Sizeof(nDriverAPIVersion)),
unsafe.Pointer(&nDriverAPIVersion),
uint32(unsafe.Sizeof(nDriverAPIVersion)),
nil,
nil,
)if err != nil {
return nil, err
}return &nDriverAPIVersion, err
}func (api *NdisApi) GetTcpipBoundAdaptersInfo() (*TCPAdapterList, error) {
var tcpAdapterList TCPAdapterListerr := api.DeviceIoControl(
IOCTL_NDISRD_GET_TCPIP_INTERFACES,
unsafe.Pointer(&tcpAdapterList),
uint32(unsafe.Sizeof(tcpAdapterList)),
unsafe.Pointer(&tcpAdapterList),
uint32(unsafe.Sizeof(tcpAdapterList)),
nil,
nil,
)if err != nil {
return nil, err
}return &tcpAdapterList, nil
}
`
Also, I created a test to see if the results are correct:
`
package ndis_test
import (
“fmt”
“testing”“github.com/lagzap/ndis-go/ndis”
“github.com/stretchr/testify/assert”
)func TestNdisApi_GetVersion(t *testing.T) {
api, err := ndis.NewNdisApi()
if err != nil {
t.Fatalf(“Failed to create NdisApi: %v”, err)
}version, err := api.GetVersion()
if err != nil {
t.Fatalf(“Failed to get version: %v”, err)
}fmt.Printf(“NDIS Driver Version: %v\n”, version)
assert.NotZero(t, version, “Version should not be zero”)
assert.NoError(t, err, “There should be no error when getting version”)
}func TestNdisApi_GetTcpipBoundAdaptersInfo(t *testing.T) {
api, err := ndis.NewNdisApi()
if err != nil {
t.Fatalf(“Failed to create NdisApi: %v”, err)
}adaptersInfo, err := api.GetTcpipBoundAdaptersInfo()
if err != nil {
t.Fatalf(“Failed to get list: %v”, err)
}for i := range adaptersInfo.AdapterCount {
nameBytes := adaptersInfo.AdapterNameList[i]
fmt.Printf(“NDIS List: %v\n”, string(nameBytes[:]))
}assert.NotZero(t, adaptersInfo.AdapterCount, “List should not be zero”)
assert.NoError(t, err, “There should be no error when getting version”)
}`
And this is the result:
=== RUN TestNdisApi_GetVersion
NDIS Driver Version: 0xc00009c928
— PASS: TestNdisApi_GetVersion (0.00s)
=== RUN TestNdisApi_GetTcpipBoundAdaptersInfo
NDIS List: \DEVICE\{ED78279B-9E2E-4C66-AEE8-793EFB217C27}
NDIS List: \DEVICE\{FF9AC243-7969-4F09-BD77-AF6C2C6A65B2}
NDIS List: \DEVICE\{40FF7482-C93F-4892-9A57-FDB19D966B6E}
NDIS List: \DEVICE\{12C7B741-5C7B-4147-B9A7-A5A2E71D5E9F}
NDIS List: \DEVICE\{A88A6FB4-497C-4464-BBA7-F48BC135DD07}
NDIS List: \DEVICE\{9353CCF4-21B8-44BA-8E2B-CA3F156FD2B1}
NDIS List: \DEVICE\{B404DFD0-745B-4C91-B5C7-BA78647826B8}
NDIS List: \DEVICE\{423C1CD9-E2E9-4821-A3A4-36E3EBBA7FA2}
NDIS List: \DEVICE\{0E2EB66C-DF42-4786-A1BF-23621E04B1A1}
NDIS List: \DEVICE\{601E27D7-7B79-498D-B121-CF3942AA124A}
NDIS List: \DEVICE\{8CF058FF-AF7F-418F-8F08-60D745F68CD5}
NDIS List: \DEVICE\{0C10FCBB-4201-4B6D-848F-6675E672F9BC}
NDIS List: \DEVICE\{1D8A9E21-80A0-404B-A563-3940C023C60F}
NDIS List: \DEVICE\{8BE3670D-A47D-4F23-91C4-85547DE5EDAD}
— PASS: TestNdisApi_GetTcpipBoundAdaptersInfo (0.00s)
PASS
ok command-line-arguments 0.015s
`
So, if i’m not mistaken this is communicating with the driver correctly because it’s giving me the result I want from these two. So, I went up further and tried to implement simple_packet_filter.go and network_adapter.go to able to do some real stuff
And this is the rewritten code of InitializeNetworkInterfaces from simple_packet_filter.go:
`
func (f *SimplePacketFilter) initializeNetworkInterfaces() error {
adapters, err := f.api.GetTcpipBoundAdaptersInfo()
if err != nil {
return err
}for i := range adapters.AdapterCount {
name := string(adapters.AdapterNameList[i][:])
adapterHandle := adapters.AdapterHandle[i]
currentAddress := adapters.CurrentAddress[i]
medium := adapters.AdapterMediumList[i]
mtu := adapters.MTU[i]friendlyName := ConvertWindows2000AdapterName(name)
networkAdapter := NewNetworkAdapter(f.api, adapterHandle, currentAddress, name, friendlyName, medium, mtu)
f.networkInterfaces = append(f.networkInterfaces, networkAdapter)
}return nil
}
`
and part of network_adapter.go
`
func NewNetworkAdapter(api *NdisApi, adapterHandle windows.Handle, macAddr [6]byte, internalName, friendlyName string, medium uint32, mtu uint16) *NetworkAdapter {
adapter := &NetworkAdapter{
API: api,
HardwareAddr: macAddr,
InternalName: internalName,
FriendlyName: friendlyName,
Medium: medium,
MTU: mtu,
CurrentMode: AdapterMode{
AdapterHandle: adapterHandle,
Flags: 0,
},
}
event, err := windows.CreateEvent(nil, 1, 0, “”)
if err != nil {
fmt.Println(err.Error())
return nil
}
adapter.packetEvent = event
`
And of course SetPacketEvent():
`
func (na *NetworkAdapter) SetPacketEvent() error {
return na.API.SetPacketEvent(na.CurrentMode.AdapterHandle, na.packetEvent)
}
`
and finally SetPacketEvent on ndis.go
`
type AdapterEvent struct {
AdapterHandle windows.Handle
Event windows.Handle
}
func (api *NdisApi) SetPacketEvent(adapter windows.Handle, win32Event windows.Handle) error {
var ring0Event windows.Handleif IsWindowsNTPlatform() {
// Windows NT platform
ring0Event = win32Event
} else {
// Windows 9x/ME platform
…
}adapterEvent := AdapterEvent{
AdapterHandle: adapter,
Event: ring0Event,
}err := api.DeviceIoControl(
IOCTL_NDISRD_SET_EVENT,
unsafe.Pointer(&adapterEvent),
uint32(unsafe.Sizeof(adapterEvent)),
nil,
0,
nil, // Bytes Returned
nil,
)fmt.Printf(“DeviceIoControl failed: %v\n”, err)
return err
}
`
and I get this error only:
DeviceIoControl failed: The parameter is incorrect.I’m not sure if I’m creating windows event incorrectly or what’s wrong, I even tried this instead of windows.CreateEvent():
https://github.com/docker/dockercraft/blob/master/vendor/github.com/docker/docker/pkg/system/events_windows.go#L22I’ll be happy if you help me solve this so I can develop this
October 24, 2024 at 3:21 pm #13904I would recommend paying attention to the following points:
1. Ensure that all structures used for driver communication are properly packed.
2. If you are using a 64-bit driver, make sure to build your code for 64-bit as well.
3. The adapter handle must correspond to the selected network interface.
4. The event handle should be a native Windows handle.
5. I suggest building and using the ndisapi.dll C interface in Go instead of reimplementing all the DeviceIoControl calls directly in Go.
October 24, 2024 at 11:29 pm #13907I don’t know how I didn’t think of using C interface, thank you, I think I’m going to do that.
-
AuthorPosts
- You must be logged in to reply to this topic.