1
0

client_amneziawg.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package service
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
  6. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  7. "github.com/mhsanaei/3x-ui/v3/internal/util/common"
  8. wgutil "github.com/mhsanaei/3x-ui/v3/internal/util/wireguard"
  9. )
  10. // defaultAmneziaWGSubnetBases resolves the /CIDR bases new peer addresses are
  11. // allocated from, out of the inbound's own configured server subnet(s) —
  12. // unlike WireGuard, which always falls back to a fixed 10.0.0.0/24. v6Base is
  13. // "" when the server doesn't have IPv6 enabled.
  14. func defaultAmneziaWGSubnetBases(settingsJSON string) (v4Base, v6Base string, err error) {
  15. var parsed amneziawg.InboundSettings
  16. if err := json.Unmarshal([]byte(settingsJSON), &parsed); err != nil {
  17. return "", "", fmt.Errorf("amneziawg: invalid settings: %w", err)
  18. }
  19. if parsed.Server == nil {
  20. return "", "", fmt.Errorf("amneziawg: settings missing server block")
  21. }
  22. cidr := parsed.Server.SubnetCIDR
  23. if cidr <= 0 {
  24. cidr = 24
  25. }
  26. v4Base = fmt.Sprintf("%s/%d", parsed.Server.SubnetIP, cidr)
  27. if parsed.Server.IPv6Enabled && parsed.Server.IPv6Subnet != "" {
  28. v6Base = parsed.Server.IPv6Subnet
  29. }
  30. return v4Base, v6Base, nil
  31. }
  32. // defaultAmneziaWGClients fills in blank credentials and a free tunnel address
  33. // for new clients, mutating both the typed clients and the parallel raw maps
  34. // persisted into the settings. Existing values are never overwritten, so an
  35. // edit never rotates keys. Mirrors defaultWireguardClients; crossInboundUsed
  36. // (see otherTunnelAllowedIPs) narrows which addresses are still free.
  37. func defaultAmneziaWGClients(settingsJSON string, existing, clients []model.Client, interfaceClients []any, crossInboundUsed map[string]string) error {
  38. v4Base, v6Base, err := defaultAmneziaWGSubnetBases(settingsJSON)
  39. if err != nil {
  40. return err
  41. }
  42. used := make([]string, 0)
  43. for i := range existing {
  44. used = append(used, existing[i].AllowedIPs...)
  45. }
  46. for addr := range crossInboundUsed {
  47. used = append(used, addr)
  48. }
  49. for i := range clients {
  50. c := &clients[i]
  51. if c.PrivateKey == "" && c.PublicKey == "" {
  52. priv, pub, err := wgutil.GenerateWireguardKeypair()
  53. if err != nil {
  54. return err
  55. }
  56. c.PrivateKey = priv
  57. c.PublicKey = pub
  58. } else if c.PublicKey == "" && c.PrivateKey != "" {
  59. pub, err := wgutil.PublicKeyFromPrivate(c.PrivateKey)
  60. if err != nil {
  61. return err
  62. }
  63. c.PublicKey = pub
  64. }
  65. if len(c.AllowedIPs) == 0 {
  66. // allowWidening=false: unlike WireGuard's Xray-native inbound,
  67. // AmneziaWG's kernel interface Address is exactly the configured
  68. // subnet, so an address allocated outside it would be silently
  69. // unroutable. Exhaustion here must fail loudly instead.
  70. addr, err := allocateWireguardAddress(used, v4Base, false)
  71. if err != nil {
  72. return err
  73. }
  74. allowed := []string{addr}
  75. if v6Base != "" {
  76. addr6, err := allocateWireguardAddress(used, v6Base, false)
  77. if err != nil {
  78. return err
  79. }
  80. allowed = append(allowed, addr6)
  81. }
  82. c.AllowedIPs = allowed
  83. } else {
  84. normalized, err := normalizeWireguardAllowedIPs(c.AllowedIPs)
  85. if err != nil {
  86. return err
  87. }
  88. if len(normalized) == 0 {
  89. return common.NewError("amneziawg: allowedIPs has no usable entry")
  90. }
  91. if hit := wireguardAllowedIPsCollision(normalized, used); hit != "" {
  92. if where := crossInboundUsed[hit]; where != "" {
  93. return common.NewError("amneziawg: allowedIPs entry", hit, "is already used by a client on", where)
  94. }
  95. return common.NewError("amneziawg: allowedIPs entry already used by another client:", hit)
  96. }
  97. c.AllowedIPs = normalized
  98. }
  99. used = append(used, c.AllowedIPs...)
  100. if i < len(interfaceClients) {
  101. if m, ok := interfaceClients[i].(map[string]any); ok {
  102. m["privateKey"] = c.PrivateKey
  103. m["publicKey"] = c.PublicKey
  104. m["allowedIPs"] = c.AllowedIPs
  105. if c.PreSharedKey != "" {
  106. m["preSharedKey"] = c.PreSharedKey
  107. }
  108. interfaceClients[i] = m
  109. }
  110. }
  111. }
  112. return nil
  113. }