github.com/metacubex/sing-tun@v0.2.7-0.20240512075008-89e7c6208eec/internal/winipcfg/winipcfg_test.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. 4 */ 5 6 /* 7 8 Some tests in this file require: 9 10 - A dedicated network adapter 11 Any network adapter will do. It may be virtual (WireGuardNT, Wintun, 12 etc.). The adapter name must contain string "winipcfg_test". 13 Tests will add, remove, flush DNS servers, change adapter IP address, manipulate 14 routes etc. 15 The adapter will not be returned to previous state, so use an expendable one. 16 17 - Elevation 18 Run go test as Administrator 19 20 */ 21 22 package winipcfg 23 24 import ( 25 "net/netip" 26 "strings" 27 "syscall" 28 "testing" 29 "time" 30 31 "golang.org/x/sys/windows" 32 ) 33 34 const ( 35 testInterfaceMarker = "winipcfg_test" // The interface we will use for testing must contain this string in its name 36 ) 37 38 // TODO: Add IPv6 tests. 39 var ( 40 nonexistantIPv4ToAdd = netip.MustParsePrefix("172.16.1.114/24") 41 nonexistentRouteIPv4ToAdd = RouteData{ 42 Destination: netip.MustParsePrefix("172.16.200.0/24"), 43 NextHop: netip.MustParseAddr("172.16.1.2"), 44 Metric: 0, 45 } 46 dnsesToSet = []netip.Addr{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("8.8.4.4")} 47 ) 48 49 func runningElevated() bool { 50 var process windows.Token 51 err := windows.OpenProcessToken(windows.CurrentProcess(), windows.TOKEN_QUERY, &process) 52 if err != nil { 53 return false 54 } 55 defer process.Close() 56 return process.IsElevated() 57 } 58 59 func getTestInterface() (*IPAdapterAddresses, error) { 60 ifcs, err := GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagIncludeAll) 61 if err != nil { 62 return nil, err 63 } 64 65 marker := strings.ToLower(testInterfaceMarker) 66 for _, ifc := range ifcs { 67 if strings.Contains(strings.ToLower(ifc.FriendlyName()), marker) { 68 return ifc, nil 69 } 70 } 71 72 return nil, windows.ERROR_NOT_FOUND 73 } 74 75 func getTestIPInterface(family AddressFamily) (*MibIPInterfaceRow, error) { 76 ifc, err := getTestInterface() 77 if err != nil { 78 return nil, err 79 } 80 81 return ifc.LUID.IPInterface(family) 82 } 83 84 func TestAdaptersAddresses(t *testing.T) { 85 ifcs, err := GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagIncludeAll) 86 if err != nil { 87 t.Errorf("GetAdaptersAddresses() returned error: %w", err) 88 } else if ifcs == nil { 89 t.Errorf("GetAdaptersAddresses() returned nil.") 90 } else if len(ifcs) == 0 { 91 t.Errorf("GetAdaptersAddresses() returned empty.") 92 } else { 93 for _, i := range ifcs { 94 i.AdapterName() 95 i.DNSSuffix() 96 i.Description() 97 i.FriendlyName() 98 i.PhysicalAddress() 99 i.DHCPv6ClientDUID() 100 for dnsSuffix := i.FirstDNSSuffix; dnsSuffix != nil; dnsSuffix = dnsSuffix.Next { 101 _ = dnsSuffix.String() 102 } 103 } 104 } 105 106 ifcs, err = GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagDefault) 107 108 for _, i := range ifcs { 109 ifc, err := i.LUID.Interface() 110 if err != nil { 111 t.Errorf("LUID.Interface() returned an error: %w", err) 112 continue 113 } else if ifc == nil { 114 t.Errorf("LUID.Interface() returned nil.") 115 continue 116 } 117 } 118 119 for _, i := range ifcs { 120 guid, err := i.LUID.GUID() 121 if err != nil { 122 t.Errorf("LUID.GUID() returned an error: %w", err) 123 continue 124 } 125 if guid == nil { 126 t.Error("LUID.GUID() returned nil.") 127 continue 128 } 129 130 luid, err := LUIDFromGUID(guid) 131 if err != nil { 132 t.Errorf("LUIDFromGUID() returned an error: %w", err) 133 continue 134 } 135 if luid != i.LUID { 136 t.Errorf("LUIDFromGUID() returned LUID %d, although expected was %d.", luid, i.LUID) 137 continue 138 } 139 } 140 } 141 142 func TestIPInterface(t *testing.T) { 143 ifcs, err := GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagDefault) 144 if err != nil { 145 t.Errorf("GetAdaptersAddresses() returned error: %w", err) 146 } 147 148 for _, i := range ifcs { 149 _, err := i.LUID.IPInterface(windows.AF_INET) 150 if err == windows.ERROR_NOT_FOUND { 151 // Ignore isatap and similar adapters without IPv4. 152 continue 153 } 154 if err != nil { 155 t.Errorf("LUID.IPInterface(%s) returned an error: %w", i.FriendlyName(), err) 156 } 157 158 _, err = i.LUID.IPInterface(windows.AF_INET6) 159 if err != nil { 160 t.Errorf("LUID.IPInterface(%s) returned an error: %w", i.FriendlyName(), err) 161 } 162 } 163 } 164 165 func TestIPInterfaces(t *testing.T) { 166 tab, err := GetIPInterfaceTable(windows.AF_UNSPEC) 167 if err != nil { 168 t.Errorf("GetIPInterfaceTable() returned an error: %w", err) 169 return 170 } else if tab == nil { 171 t.Error("GetIPInterfaceTable() returned nil.") 172 } 173 174 if len(tab) == 0 { 175 t.Error("GetIPInterfaceTable() returned an empty slice.") 176 return 177 } 178 } 179 180 func TestIPChangeMetric(t *testing.T) { 181 ipifc, err := getTestIPInterface(windows.AF_INET) 182 if err != nil { 183 t.Errorf("getTestIPInterface() returned an error: %w", err) 184 return 185 } 186 if !runningElevated() { 187 t.Errorf("%s requires elevation", t.Name()) 188 return 189 } 190 191 var changed bool 192 cb, err := RegisterInterfaceChangeCallback(func(notificationType MibNotificationType, iface *MibIPInterfaceRow) { 193 if iface == nil || iface.InterfaceLUID != ipifc.InterfaceLUID { 194 return 195 } 196 switch notificationType { 197 case MibParameterNotification: 198 changed = true 199 } 200 }) 201 if err != nil { 202 t.Errorf("RegisterInterfaceChangeCallback() returned error: %w", err) 203 return 204 } 205 defer func() { 206 err = cb.Unregister() 207 if err != nil { 208 t.Errorf("UnregisterInterfaceChangeCallback() returned error: %w", err) 209 } 210 }() 211 212 useAutomaticMetric := ipifc.UseAutomaticMetric 213 metric := ipifc.Metric 214 215 newMetric := uint32(100) 216 if newMetric == metric { 217 newMetric = 200 218 } 219 220 ipifc.UseAutomaticMetric = false 221 ipifc.Metric = newMetric 222 err = ipifc.Set() 223 if err != nil { 224 t.Errorf("MibIPInterfaceRow.Set() returned an error: %w", err) 225 } 226 227 time.Sleep(500 * time.Millisecond) 228 229 ipifc, err = getTestIPInterface(windows.AF_INET) 230 if err != nil { 231 t.Errorf("getTestIPInterface() returned an error: %w", err) 232 return 233 } 234 if ipifc.Metric != newMetric { 235 t.Errorf("Expected metric: %d; actual metric: %d", newMetric, ipifc.Metric) 236 } 237 if ipifc.UseAutomaticMetric { 238 t.Error("UseAutomaticMetric is true although it's set to false.") 239 } 240 if !changed { 241 t.Errorf("Notification handler has not been called on metric change.") 242 } 243 changed = false 244 245 ipifc.UseAutomaticMetric = useAutomaticMetric 246 ipifc.Metric = metric 247 err = ipifc.Set() 248 if err != nil { 249 t.Errorf("MibIPInterfaceRow.Set() returned an error: %w", err) 250 } 251 252 time.Sleep(500 * time.Millisecond) 253 254 ipifc, err = getTestIPInterface(windows.AF_INET) 255 if err != nil { 256 t.Errorf("getTestIPInterface() returned an error: %w", err) 257 return 258 } 259 if ipifc.Metric != metric { 260 t.Errorf("Expected metric: %d; actual metric: %d", metric, ipifc.Metric) 261 } 262 if ipifc.UseAutomaticMetric != useAutomaticMetric { 263 t.Errorf("UseAutomaticMetric is %v although %v is expected.", ipifc.UseAutomaticMetric, useAutomaticMetric) 264 } 265 if !changed { 266 t.Errorf("Notification handler has not been called on metric change.") 267 } 268 } 269 270 func TestIPChangeMTU(t *testing.T) { 271 ipifc, err := getTestIPInterface(windows.AF_INET) 272 if err != nil { 273 t.Errorf("getTestIPInterface() returned an error: %w", err) 274 return 275 } 276 if !runningElevated() { 277 t.Errorf("%s requires elevation", t.Name()) 278 return 279 } 280 281 prevMTU := ipifc.NLMTU 282 mtuToSet := prevMTU - 1 283 ipifc.NLMTU = mtuToSet 284 err = ipifc.Set() 285 if err != nil { 286 t.Errorf("Interface.Set() returned error: %w", err) 287 } 288 289 time.Sleep(500 * time.Millisecond) 290 291 ipifc, err = getTestIPInterface(windows.AF_INET) 292 if err != nil { 293 t.Errorf("getTestIPInterface() returned an error: %w", err) 294 return 295 } 296 if ipifc.NLMTU != mtuToSet { 297 t.Errorf("Interface.NLMTU is %d although %d is expected.", ipifc.NLMTU, mtuToSet) 298 } 299 300 ipifc.NLMTU = prevMTU 301 err = ipifc.Set() 302 if err != nil { 303 t.Errorf("Interface.Set() returned error: %w", err) 304 } 305 306 time.Sleep(500 * time.Millisecond) 307 308 ipifc, err = getTestIPInterface(windows.AF_INET) 309 if err != nil { 310 t.Errorf("getTestIPInterface() returned an error: %w", err) 311 } 312 if ipifc.NLMTU != prevMTU { 313 t.Errorf("Interface.NLMTU is %d although %d is expected.", ipifc.NLMTU, prevMTU) 314 } 315 } 316 317 func TestGetIfRow(t *testing.T) { 318 ifc, err := getTestInterface() 319 if err != nil { 320 t.Errorf("getTestInterface() returned an error: %w", err) 321 return 322 } 323 324 row, err := ifc.LUID.Interface() 325 if err != nil { 326 t.Errorf("LUID.Interface() returned an error: %w", err) 327 return 328 } 329 330 row.Alias() 331 row.Description() 332 row.PhysicalAddress() 333 row.PermanentPhysicalAddress() 334 } 335 336 func TestGetIfRows(t *testing.T) { 337 tab, err := GetIfTable2Ex(MibIfEntryNormal) 338 if err != nil { 339 t.Errorf("GetIfTable2Ex() returned an error: %w", err) 340 return 341 } else if tab == nil { 342 t.Errorf("GetIfTable2Ex() returned nil") 343 return 344 } 345 346 for i := range tab { 347 tab[i].Alias() 348 tab[i].Description() 349 tab[i].PhysicalAddress() 350 tab[i].PermanentPhysicalAddress() 351 } 352 } 353 354 func TestUnicastIPAddress(t *testing.T) { 355 _, err := GetUnicastIPAddressTable(windows.AF_UNSPEC) 356 if err != nil { 357 t.Errorf("GetUnicastAddresses() returned an error: %w", err) 358 return 359 } 360 } 361 362 func TestAddDeleteIPAddress(t *testing.T) { 363 ifc, err := getTestInterface() 364 if err != nil { 365 t.Errorf("getTestInterface() returned an error: %w", err) 366 return 367 } 368 if !runningElevated() { 369 t.Errorf("%s requires elevation", t.Name()) 370 return 371 } 372 373 addr, err := ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr()) 374 if err == nil { 375 t.Errorf("Unicast address %s already exists. Please set nonexistantIPv4ToAdd appropriately.", nonexistantIPv4ToAdd.Addr().String()) 376 return 377 } else if err != windows.ERROR_NOT_FOUND { 378 t.Errorf("LUID.IPAddress() returned an error: %w", err) 379 return 380 } 381 382 var created, deleted bool 383 cb, err := RegisterUnicastAddressChangeCallback(func(notificationType MibNotificationType, addr *MibUnicastIPAddressRow) { 384 if addr == nil || addr.InterfaceLUID != ifc.LUID { 385 return 386 } 387 switch notificationType { 388 case MibAddInstance: 389 created = true 390 case MibDeleteInstance: 391 deleted = true 392 } 393 }) 394 if err != nil { 395 t.Errorf("RegisterUnicastAddressChangeCallback() returned an error: %w", err) 396 } else { 397 defer cb.Unregister() 398 } 399 var count int 400 for addr := ifc.FirstUnicastAddress; addr != nil; addr = addr.Next { 401 count-- 402 } 403 err = ifc.LUID.AddIPAddresses([]netip.Prefix{nonexistantIPv4ToAdd}) 404 if err != nil { 405 t.Errorf("LUID.AddIPAddresses() returned an error: %w", err) 406 } 407 408 time.Sleep(500 * time.Millisecond) 409 410 ifc, _ = getTestInterface() 411 for addr := ifc.FirstUnicastAddress; addr != nil; addr = addr.Next { 412 count++ 413 } 414 if count != 1 { 415 t.Errorf("After adding there are %d new interface(s).", count) 416 } 417 addr, err = ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr()) 418 if err != nil { 419 t.Errorf("LUID.IPAddress() returned an error: %w", err) 420 } else if addr == nil { 421 t.Errorf("Unicast address %s still doesn't exist, although it's added successfully.", nonexistantIPv4ToAdd.Addr().String()) 422 } 423 if !created { 424 t.Errorf("Notification handler has not been called on add.") 425 } 426 427 err = ifc.LUID.DeleteIPAddress(nonexistantIPv4ToAdd) 428 if err != nil { 429 t.Errorf("LUID.DeleteIPAddress() returned an error: %w", err) 430 } 431 432 time.Sleep(500 * time.Millisecond) 433 434 addr, err = ifc.LUID.IPAddress(nonexistantIPv4ToAdd.Addr()) 435 if err == nil { 436 t.Errorf("Unicast address %s still exists, although it's deleted successfully.", nonexistantIPv4ToAdd.Addr().String()) 437 } else if err != windows.ERROR_NOT_FOUND { 438 t.Errorf("LUID.IPAddress() returned an error: %w", err) 439 } 440 if !deleted { 441 t.Errorf("Notification handler has not been called on delete.") 442 } 443 } 444 445 func TestGetRoutes(t *testing.T) { 446 _, err := GetIPForwardTable2(windows.AF_UNSPEC) 447 if err != nil { 448 t.Errorf("GetIPForwardTable2() returned error: %w", err) 449 } 450 } 451 452 func TestAddDeleteRoute(t *testing.T) { 453 findRoute := func(luid LUID, dest netip.Prefix) ([]MibIPforwardRow2, error) { 454 var family AddressFamily 455 if dest.Addr().Is4() { 456 family = windows.AF_INET 457 } else if dest.Addr().Is6() { 458 family = windows.AF_INET6 459 } else { 460 return nil, windows.ERROR_INVALID_PARAMETER 461 } 462 r, err := GetIPForwardTable2(family) 463 if err != nil { 464 return nil, err 465 } 466 matches := make([]MibIPforwardRow2, 0, len(r)) 467 for _, route := range r { 468 if route.InterfaceLUID == luid && route.DestinationPrefix.PrefixLength == uint8(dest.Bits()) && route.DestinationPrefix.RawPrefix.Family == family && route.DestinationPrefix.RawPrefix.Addr() == dest.Addr() { 469 matches = append(matches, route) 470 } 471 } 472 return matches, nil 473 } 474 475 ifc, err := getTestInterface() 476 if err != nil { 477 t.Errorf("getTestInterface() returned an error: %w", err) 478 return 479 } 480 if !runningElevated() { 481 t.Errorf("%s requires elevation", t.Name()) 482 return 483 } 484 485 _, err = ifc.LUID.Route(nonexistentRouteIPv4ToAdd.Destination, nonexistentRouteIPv4ToAdd.NextHop) 486 if err == nil { 487 t.Error("LUID.Route() returned a route although it isn't added yet. Have you forgot to set nonexistentRouteIPv4ToAdd appropriately?") 488 return 489 } else if err != windows.ERROR_NOT_FOUND { 490 t.Errorf("LUID.Route() returned an error: %w", err) 491 return 492 } 493 494 routes, err := findRoute(ifc.LUID, nonexistentRouteIPv4ToAdd.Destination) 495 if err != nil { 496 t.Errorf("findRoute() returned an error: %w", err) 497 } else if len(routes) != 0 { 498 t.Errorf("findRoute() returned %d items although the route isn't added yet. Have you forgot to set nonexistentRouteIPv4ToAdd appropriately?", len(routes)) 499 } 500 501 var created, deleted bool 502 cb, err := RegisterRouteChangeCallback(func(notificationType MibNotificationType, route *MibIPforwardRow2) { 503 switch notificationType { 504 case MibAddInstance: 505 created = true 506 case MibDeleteInstance: 507 deleted = true 508 } 509 }) 510 if err != nil { 511 t.Errorf("RegisterRouteChangeCallback() returned an error: %w", err) 512 } else { 513 defer cb.Unregister() 514 } 515 err = ifc.LUID.AddRoute(nonexistentRouteIPv4ToAdd.Destination, nonexistentRouteIPv4ToAdd.NextHop, nonexistentRouteIPv4ToAdd.Metric) 516 if err != nil { 517 t.Errorf("LUID.AddRoute() returned an error: %w", err) 518 } 519 520 time.Sleep(500 * time.Millisecond) 521 522 route, err := ifc.LUID.Route(nonexistentRouteIPv4ToAdd.Destination, nonexistentRouteIPv4ToAdd.NextHop) 523 if err == windows.ERROR_NOT_FOUND { 524 t.Error("LUID.Route() returned nil although the route is added successfully.") 525 } else if err != nil { 526 t.Errorf("LUID.Route() returned an error: %w", err) 527 } else if route.DestinationPrefix.RawPrefix.Addr() != nonexistentRouteIPv4ToAdd.Destination.Addr() || route.NextHop.Addr() != nonexistentRouteIPv4ToAdd.NextHop { 528 t.Error("LUID.Route() returned a wrong route!") 529 } 530 if !created { 531 t.Errorf("Route handler has not been called on add.") 532 } 533 534 routes, err = findRoute(ifc.LUID, nonexistentRouteIPv4ToAdd.Destination) 535 if err != nil { 536 t.Errorf("findRoute() returned an error: %w", err) 537 } else if len(routes) != 1 { 538 t.Errorf("findRoute() returned %d items although %d is expected.", len(routes), 1) 539 } else if routes[0].DestinationPrefix.RawPrefix.Addr() != nonexistentRouteIPv4ToAdd.Destination.Addr() { 540 t.Errorf("findRoute() returned a wrong route. Dest: %s; expected: %s.", routes[0].DestinationPrefix.RawPrefix.Addr().String(), nonexistentRouteIPv4ToAdd.Destination.Addr().String()) 541 } 542 543 err = ifc.LUID.DeleteRoute(nonexistentRouteIPv4ToAdd.Destination, nonexistentRouteIPv4ToAdd.NextHop) 544 if err != nil { 545 t.Errorf("LUID.DeleteRoute() returned an error: %w", err) 546 } 547 548 time.Sleep(500 * time.Millisecond) 549 550 _, err = ifc.LUID.Route(nonexistentRouteIPv4ToAdd.Destination, nonexistentRouteIPv4ToAdd.NextHop) 551 if err == nil { 552 t.Error("LUID.Route() returned a route although it is removed successfully.") 553 } else if err != windows.ERROR_NOT_FOUND { 554 t.Errorf("LUID.Route() returned an error: %w", err) 555 } 556 if !deleted { 557 t.Errorf("Route handler has not been called on delete.") 558 } 559 560 routes, err = findRoute(ifc.LUID, nonexistentRouteIPv4ToAdd.Destination) 561 if err != nil { 562 t.Errorf("findRoute() returned an error: %w", err) 563 } else if len(routes) != 0 { 564 t.Errorf("findRoute() returned %d items although the route is deleted successfully.", len(routes)) 565 } 566 } 567 568 func TestFlushDNS(t *testing.T) { 569 ifc, err := getTestInterface() 570 if err != nil { 571 t.Errorf("getTestInterface() returned an error: %w", err) 572 return 573 } 574 if !runningElevated() { 575 t.Errorf("%s requires elevation", t.Name()) 576 return 577 } 578 579 prevDNSes, err := ifc.LUID.DNS() 580 if err != nil { 581 t.Errorf("LUID.DNS() returned an error: %w", err) 582 } 583 584 err = ifc.LUID.FlushDNS(syscall.AF_INET) 585 if err != nil { 586 t.Errorf("LUID.FlushDNS() returned an error: %w", err) 587 } 588 589 ifc, _ = getTestInterface() 590 591 n := 0 592 dns, err := ifc.LUID.DNS() 593 if err != nil { 594 t.Errorf("LUID.DNS() returned an error: %w", err) 595 } 596 for _, a := range dns { 597 if a.Is4() { 598 n++ 599 } 600 } 601 if n != 0 { 602 t.Errorf("DNSServerAddresses contains %d items, although FlushDNS is executed successfully.", n) 603 } 604 605 err = ifc.LUID.SetDNS(windows.AF_INET, prevDNSes, nil) 606 if err != nil { 607 t.Errorf("LUID.SetDNS() returned an error: %v.", err) 608 } 609 } 610 611 func TestSetDNS(t *testing.T) { 612 ifc, err := getTestInterface() 613 if err != nil { 614 t.Errorf("getTestInterface() returned an error: %w", err) 615 return 616 } 617 if !runningElevated() { 618 t.Errorf("%s requires elevation", t.Name()) 619 return 620 } 621 622 prevDNSes, err := ifc.LUID.DNS() 623 if err != nil { 624 t.Errorf("LUID.DNS() returned an error: %w", err) 625 } 626 627 err = ifc.LUID.SetDNS(windows.AF_INET, dnsesToSet, nil) 628 if err != nil { 629 t.Errorf("LUID.SetDNS() returned an error: %w", err) 630 return 631 } 632 633 ifc, _ = getTestInterface() 634 635 newDNSes, err := ifc.LUID.DNS() 636 if err != nil { 637 t.Errorf("LUID.DNS() returned an error: %w", err) 638 } else if len(newDNSes) != len(dnsesToSet) { 639 t.Errorf("dnsesToSet contains %d items, while DNSServerAddresses contains %d.", len(dnsesToSet), len(newDNSes)) 640 } else { 641 for i := range dnsesToSet { 642 if dnsesToSet[i] != newDNSes[i] { 643 t.Errorf("dnsesToSet[%d] = %s while DNSServerAddresses[%d] = %s.", i, dnsesToSet[i].String(), i, newDNSes[i].String()) 644 } 645 } 646 } 647 648 err = ifc.LUID.SetDNS(windows.AF_INET, prevDNSes, nil) 649 if err != nil { 650 t.Errorf("LUID.SetDNS() returned an error: %v.", err) 651 } 652 } 653 654 func TestAnycastIPAddress(t *testing.T) { 655 _, err := GetAnycastIPAddressTable(windows.AF_UNSPEC) 656 if err != nil { 657 t.Errorf("GetAnycastIPAddressTable() returned an error: %w", err) 658 return 659 } 660 }