syscalls_windows.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. package water
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "sync"
  8. "syscall"
  9. "unsafe"
  10. "golang.org/x/sys/windows/registry"
  11. )
  12. // To use it with windows, you need a tap driver installed on windows.
  13. // https://github.com/OpenVPN/tap-windows6
  14. // or just install OpenVPN
  15. // https://github.com/OpenVPN/openvpn
  16. const (
  17. // tapDriverKey is the location of the TAP driver key.
  18. tapDriverKey = `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`
  19. // netConfigKey is the location of the TAP adapter's network config.
  20. netConfigKey = `SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}`
  21. )
  22. var (
  23. errIfceNameNotFound = errors.New("Failed to find the name of interface")
  24. // Device Control Codes
  25. tap_win_ioctl_get_mac = tap_control_code(1, 0)
  26. tap_win_ioctl_get_version = tap_control_code(2, 0)
  27. tap_win_ioctl_get_mtu = tap_control_code(3, 0)
  28. tap_win_ioctl_get_info = tap_control_code(4, 0)
  29. tap_ioctl_config_point_to_point = tap_control_code(5, 0)
  30. tap_ioctl_set_media_status = tap_control_code(6, 0)
  31. tap_win_ioctl_config_dhcp_masq = tap_control_code(7, 0)
  32. tap_win_ioctl_get_log_line = tap_control_code(8, 0)
  33. tap_win_ioctl_config_dhcp_set_opt = tap_control_code(9, 0)
  34. tap_ioctl_config_tun = tap_control_code(10, 0)
  35. // w32 api
  36. file_device_unknown = uint32(0x00000022)
  37. nCreateEvent,
  38. nResetEvent,
  39. nGetOverlappedResult uintptr
  40. )
  41. func init() {
  42. k32, err := syscall.LoadLibrary("kernel32.dll")
  43. if err != nil {
  44. panic("LoadLibrary " + err.Error())
  45. }
  46. defer syscall.FreeLibrary(k32)
  47. nCreateEvent = getProcAddr(k32, "CreateEventW")
  48. nResetEvent = getProcAddr(k32, "ResetEvent")
  49. nGetOverlappedResult = getProcAddr(k32, "GetOverlappedResult")
  50. }
  51. func getProcAddr(lib syscall.Handle, name string) uintptr {
  52. addr, err := syscall.GetProcAddress(lib, name)
  53. if err != nil {
  54. panic(name + " " + err.Error())
  55. }
  56. return addr
  57. }
  58. func resetEvent(h syscall.Handle) error {
  59. r, _, err := syscall.Syscall(nResetEvent, 1, uintptr(h), 0, 0)
  60. if r == 0 {
  61. return err
  62. }
  63. return nil
  64. }
  65. func getOverlappedResult(h syscall.Handle, overlapped *syscall.Overlapped) (int, error) {
  66. var n int
  67. r, _, err := syscall.Syscall6(nGetOverlappedResult, 4,
  68. uintptr(h),
  69. uintptr(unsafe.Pointer(overlapped)),
  70. uintptr(unsafe.Pointer(&n)), 1, 0, 0)
  71. if r == 0 {
  72. return n, err
  73. }
  74. return n, nil
  75. }
  76. func newOverlapped() (*syscall.Overlapped, error) {
  77. var overlapped syscall.Overlapped
  78. r, _, err := syscall.Syscall6(nCreateEvent, 4, 0, 1, 0, 0, 0, 0)
  79. if r == 0 {
  80. return nil, err
  81. }
  82. overlapped.HEvent = syscall.Handle(r)
  83. return &overlapped, nil
  84. }
  85. type wfile struct {
  86. fd syscall.Handle
  87. rl sync.Mutex
  88. wl sync.Mutex
  89. ro *syscall.Overlapped
  90. wo *syscall.Overlapped
  91. }
  92. func (f *wfile) Close() error {
  93. return syscall.Close(f.fd)
  94. }
  95. func (f *wfile) Write(b []byte) (int, error) {
  96. f.wl.Lock()
  97. defer f.wl.Unlock()
  98. if err := resetEvent(f.wo.HEvent); err != nil {
  99. return 0, err
  100. }
  101. var n uint32
  102. err := syscall.WriteFile(f.fd, b, &n, f.wo)
  103. if err != nil && err != syscall.ERROR_IO_PENDING {
  104. return int(n), err
  105. }
  106. return getOverlappedResult(f.fd, f.wo)
  107. }
  108. func (f *wfile) Read(b []byte) (int, error) {
  109. f.rl.Lock()
  110. defer f.rl.Unlock()
  111. if err := resetEvent(f.ro.HEvent); err != nil {
  112. return 0, err
  113. }
  114. var done uint32
  115. err := syscall.ReadFile(f.fd, b, &done, f.ro)
  116. if err != nil && err != syscall.ERROR_IO_PENDING {
  117. return int(done), err
  118. }
  119. return getOverlappedResult(f.fd, f.ro)
  120. }
  121. func ctl_code(device_type, function, method, access uint32) uint32 {
  122. return (device_type << 16) | (access << 14) | (function << 2) | method
  123. }
  124. func tap_control_code(request, method uint32) uint32 {
  125. return ctl_code(file_device_unknown, request, method, 0)
  126. }
  127. // getdeviceid finds out a TAP device from registry, it *may* requires privileged right to prevent some weird issue.
  128. func getdeviceid(componentID string, interfaceName string) (deviceid string, err error) {
  129. k, err := registry.OpenKey(registry.LOCAL_MACHINE, tapDriverKey, registry.READ)
  130. if err != nil {
  131. return "", fmt.Errorf("Failed to open the adapter registry, TAP driver may be not installed, %v", err)
  132. }
  133. defer k.Close()
  134. // read all subkeys, it should not return an err here
  135. keys, err := k.ReadSubKeyNames(-1)
  136. if err != nil {
  137. return "", err
  138. }
  139. // find the one matched ComponentId
  140. for _, v := range keys {
  141. key, err := registry.OpenKey(registry.LOCAL_MACHINE, tapDriverKey+"\\"+v, registry.READ)
  142. if err != nil {
  143. continue
  144. }
  145. val, _, err := key.GetStringValue("ComponentId")
  146. if err != nil {
  147. key.Close()
  148. continue
  149. }
  150. if val == componentID {
  151. val, _, err = key.GetStringValue("NetCfgInstanceId")
  152. if err != nil {
  153. key.Close()
  154. continue
  155. }
  156. if len(interfaceName) > 0 {
  157. key2 := fmt.Sprintf("%s\\%s\\Connection", netConfigKey, val)
  158. k2, err := registry.OpenKey(registry.LOCAL_MACHINE, key2, registry.READ)
  159. if err != nil {
  160. continue
  161. }
  162. defer k2.Close()
  163. val, _, err := k2.GetStringValue("Name")
  164. if err != nil || val != interfaceName {
  165. continue
  166. }
  167. }
  168. key.Close()
  169. return val, nil
  170. }
  171. key.Close()
  172. }
  173. if len(interfaceName) > 0 {
  174. return "", fmt.Errorf("Failed to find the tap device in registry with specified ComponentId '%s' and InterfaceName '%s', TAP driver may be not installed or you may have specified an interface name that doesn't exist", componentID, interfaceName)
  175. }
  176. return "", fmt.Errorf("Failed to find the tap device in registry with specified ComponentId '%s', TAP driver may be not installed", componentID)
  177. }
  178. // setStatus is used to bring up or bring down the interface
  179. func setStatus(fd syscall.Handle, status bool) error {
  180. var bytesReturned uint32
  181. rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
  182. code := []byte{0x00, 0x00, 0x00, 0x00}
  183. if status {
  184. code[0] = 0x01
  185. }
  186. return syscall.DeviceIoControl(fd, tap_ioctl_set_media_status, &code[0], uint32(4), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
  187. }
  188. // setTUN is used to configure the IP address in the underlying driver when using TUN
  189. func setTUN(fd syscall.Handle, network string) error {
  190. var bytesReturned uint32
  191. rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
  192. localIP, remoteNet, err := net.ParseCIDR(network)
  193. if err != nil {
  194. return fmt.Errorf("Failed to parse network CIDR in config, %v", err)
  195. }
  196. if localIP.To4() == nil {
  197. return fmt.Errorf("Provided network(%s) is not a valid IPv4 address", network)
  198. }
  199. code2 := make([]byte, 0, 12)
  200. code2 = append(code2, localIP.To4()[:4]...)
  201. code2 = append(code2, remoteNet.IP.To4()[:4]...)
  202. code2 = append(code2, remoteNet.Mask[:4]...)
  203. if len(code2) != 12 {
  204. return fmt.Errorf("Provided network(%s) is not valid", network)
  205. }
  206. if err := syscall.DeviceIoControl(fd, tap_ioctl_config_tun, &code2[0], uint32(12), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil); err != nil {
  207. return err
  208. }
  209. return nil
  210. }
  211. // openDev find and open an interface.
  212. func openDev(config Config) (ifce *Interface, err error) {
  213. // find the device in registry.
  214. deviceid, err := getdeviceid(config.PlatformSpecificParams.ComponentID, config.PlatformSpecificParams.InterfaceName)
  215. if err != nil {
  216. return nil, err
  217. }
  218. path := "\\\\.\\Global\\" + deviceid + ".tap"
  219. pathp, err := syscall.UTF16PtrFromString(path)
  220. if err != nil {
  221. return nil, err
  222. }
  223. // type Handle uintptr
  224. file, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, uint32(syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE), nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_SYSTEM|syscall.FILE_FLAG_OVERLAPPED, 0)
  225. // if err hanppens, close the interface.
  226. defer func() {
  227. if err != nil {
  228. syscall.Close(file)
  229. }
  230. if err := recover(); err != nil {
  231. syscall.Close(file)
  232. }
  233. }()
  234. if err != nil {
  235. return nil, err
  236. }
  237. var bytesReturned uint32
  238. // find the mac address of tap device, use this to find the name of interface
  239. mac := make([]byte, 6)
  240. err = syscall.DeviceIoControl(file, tap_win_ioctl_get_mac, &mac[0], uint32(len(mac)), &mac[0], uint32(len(mac)), &bytesReturned, nil)
  241. if err != nil {
  242. return nil, err
  243. }
  244. // fd := os.NewFile(uintptr(file), path)
  245. ro, err := newOverlapped()
  246. if err != nil {
  247. return
  248. }
  249. wo, err := newOverlapped()
  250. if err != nil {
  251. return
  252. }
  253. fd := &wfile{fd: file, ro: ro, wo: wo}
  254. ifce = &Interface{isTAP: (config.DeviceType == TAP), ReadWriteCloser: fd}
  255. // bring up device.
  256. if err := setStatus(file, true); err != nil {
  257. return nil, err
  258. }
  259. //TUN
  260. if config.DeviceType == TUN {
  261. if err := setTUN(file, config.PlatformSpecificParams.Network); err != nil {
  262. return nil, err
  263. }
  264. }
  265. // find the name of tap interface(u need it to set the ip or other command)
  266. ifces, err := net.Interfaces()
  267. if err != nil {
  268. return
  269. }
  270. for _, v := range ifces {
  271. if len(v.HardwareAddr) < 6 {
  272. continue
  273. }
  274. if bytes.Equal(v.HardwareAddr[:6], mac[:6]) {
  275. ifce.name = v.Name
  276. return
  277. }
  278. }
  279. return nil, errIfceNameNotFound
  280. }