1
0

client_wireguard.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package service
  2. import (
  3. "net/netip"
  4. "strconv"
  5. "strings"
  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. const defaultWireguardBase = "10.0.0.0/24"
  11. func keepAliveStr(seconds int) string {
  12. if seconds <= 0 {
  13. return ""
  14. }
  15. return strconv.Itoa(seconds)
  16. }
  17. func wireguardHostAddr(s string) netip.Addr {
  18. s = strings.TrimSpace(s)
  19. if s == "" {
  20. return netip.Addr{}
  21. }
  22. if p, err := netip.ParsePrefix(s); err == nil {
  23. return p.Addr()
  24. }
  25. if a, err := netip.ParseAddr(s); err == nil {
  26. return a
  27. }
  28. return netip.Addr{}
  29. }
  30. func wireguardAllocationBase(used []string, fallback string) string {
  31. for _, u := range used {
  32. a := wireguardHostAddr(u)
  33. if !a.IsValid() || !a.Is4() || a.IsUnspecified() {
  34. continue
  35. }
  36. if p, err := a.Prefix(24); err == nil {
  37. return p.String()
  38. }
  39. }
  40. return fallback
  41. }
  42. // allocateWireguardAddress returns the first free /32 host address in base that
  43. // is not already present in used. The server holds the first host (.1), so
  44. // allocation starts at the second host (.2).
  45. func allocateWireguardAddress(used []string, base string) (string, error) {
  46. if base == "" {
  47. base = defaultWireguardBase
  48. }
  49. prefix, err := netip.ParsePrefix(base)
  50. if err != nil {
  51. return "", err
  52. }
  53. taken := make(map[netip.Addr]struct{}, len(used))
  54. for _, u := range used {
  55. if a := wireguardHostAddr(u); a.IsValid() {
  56. taken[a] = struct{}{}
  57. }
  58. }
  59. addr := prefix.Masked().Addr().Next().Next()
  60. for prefix.Contains(addr) {
  61. if _, ok := taken[addr]; !ok {
  62. return addr.String() + "/32", nil
  63. }
  64. addr = addr.Next()
  65. }
  66. return "", common.NewError("wireguard: no free address available in", base)
  67. }
  68. // normalizeWireguardAllowedIPs validates user-supplied allowedIPs entries and
  69. // canonicalizes them: bare addresses become single-host prefixes, duplicates drop.
  70. func normalizeWireguardAllowedIPs(values []string) ([]string, error) {
  71. out := make([]string, 0, len(values))
  72. seen := make(map[string]struct{}, len(values))
  73. for _, v := range values {
  74. v = strings.TrimSpace(v)
  75. if v == "" {
  76. continue
  77. }
  78. p, err := netip.ParsePrefix(v)
  79. if err != nil {
  80. a, aErr := netip.ParseAddr(v)
  81. if aErr != nil {
  82. return nil, common.NewError("wireguard: invalid allowedIPs entry:", v)
  83. }
  84. p = netip.PrefixFrom(a, a.BitLen())
  85. }
  86. norm := p.String()
  87. if _, dup := seen[norm]; dup {
  88. continue
  89. }
  90. seen[norm] = struct{}{}
  91. out = append(out, norm)
  92. }
  93. return out, nil
  94. }
  95. func wireguardAllowedIPsCollision(entries, used []string) string {
  96. taken := make(map[string]struct{}, len(used))
  97. for _, u := range used {
  98. taken[strings.TrimSpace(u)] = struct{}{}
  99. }
  100. for _, e := range entries {
  101. if _, ok := taken[e]; ok {
  102. return e
  103. }
  104. }
  105. return ""
  106. }
  107. // defaultWireguardClients fills in blank WireGuard credentials for newly added
  108. // clients: a generated keypair when none was provided, a derived public key when
  109. // only a private key was given, and a unique tunnel address allocated from the
  110. // inbound's subnet. It mutates both the typed clients and the parallel raw client
  111. // maps that get persisted into the inbound settings. Existing values are never
  112. // overwritten, so editing a client never rotates its keys.
  113. func defaultWireguardClients(existing, clients []model.Client, interfaceClients []any) error {
  114. used := make([]string, 0)
  115. for i := range existing {
  116. used = append(used, existing[i].AllowedIPs...)
  117. }
  118. base := wireguardAllocationBase(used, defaultWireguardBase)
  119. for i := range clients {
  120. c := &clients[i]
  121. if c.PrivateKey == "" && c.PublicKey == "" {
  122. priv, pub, err := wgutil.GenerateWireguardKeypair()
  123. if err != nil {
  124. return err
  125. }
  126. c.PrivateKey = priv
  127. c.PublicKey = pub
  128. } else if c.PublicKey == "" && c.PrivateKey != "" {
  129. pub, err := wgutil.PublicKeyFromPrivate(c.PrivateKey)
  130. if err != nil {
  131. return err
  132. }
  133. c.PublicKey = pub
  134. }
  135. if len(c.AllowedIPs) == 0 {
  136. addr, err := allocateWireguardAddress(used, base)
  137. if err != nil {
  138. return err
  139. }
  140. c.AllowedIPs = []string{addr}
  141. } else {
  142. normalized, err := normalizeWireguardAllowedIPs(c.AllowedIPs)
  143. if err != nil {
  144. return err
  145. }
  146. if len(normalized) == 0 {
  147. return common.NewError("wireguard: allowedIPs has no usable entry")
  148. }
  149. if hit := wireguardAllowedIPsCollision(normalized, used); hit != "" {
  150. return common.NewError("wireguard: allowedIPs entry already used by another client:", hit)
  151. }
  152. c.AllowedIPs = normalized
  153. }
  154. used = append(used, c.AllowedIPs...)
  155. if i < len(interfaceClients) {
  156. if m, ok := interfaceClients[i].(map[string]any); ok {
  157. m["privateKey"] = c.PrivateKey
  158. m["publicKey"] = c.PublicKey
  159. m["allowedIPs"] = c.AllowedIPs
  160. if c.PreSharedKey != "" {
  161. m["preSharedKey"] = c.PreSharedKey
  162. }
  163. if c.KeepAlive > 0 {
  164. m["keepAlive"] = c.KeepAlive
  165. }
  166. interfaceClients[i] = m
  167. }
  168. }
  169. }
  170. return nil
  171. }