types.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Package amneziawg holds the AmneziaWG protocol's shared, DB-backed shapes
  2. // (Instance, Peer, Obfuscation31, ServerSettings/InboundSettings) and the
  3. // pure functions that derive an Instance from a stored inbound row. It has
  4. // no OS dependency of its own: internal/amneziawgnet embeds amneziawg-go
  5. // over a gVisor netstack and owns the actual running interfaces, one
  6. // Manager-managed Device per desired Instance -- see that package's Manager
  7. // for the reconcile-on-tick lifecycle (modeled on internal/mtproto's own
  8. // Manager), and instance.go's own doc comment for how this package's role
  9. // narrowed to protocol-shape-only after the kernel-module (DKMS) + awg-quick
  10. // architecture this fork originally shipped was retired.
  11. package amneziawg
  12. import "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  13. // Obfuscation31 is an AmneziaWG 3.1 obfuscation parameter set (junk packets,
  14. // padding, magic headers, the five CPS signature-packet slots, and the 3.x
  15. // header-protection/content-padding/timing/boolean fields). The same values
  16. // must be applied on both ends of a tunnel, so the server stores them and
  17. // every client config inherits them verbatim.
  18. type Obfuscation31 struct {
  19. Jc int `json:"jc"`
  20. Jmin int `json:"jmin"`
  21. Jmax int `json:"jmax"`
  22. S1 int `json:"s1"`
  23. S2 int `json:"s2"`
  24. S3 int `json:"s3"`
  25. S4 int `json:"s4"`
  26. H1 string `json:"h1"`
  27. H2 string `json:"h2"`
  28. H3 string `json:"h3"`
  29. H4 string `json:"h4"`
  30. // I1-I5 are the real protocol's five CPS signature-packet slots
  31. // (confirmed against amneziawg-go v3.0.3's device/uapi.go: "i1"
  32. // through "i5" are five independent UAPI setters, device.ipackets[0..4],
  33. // all parsed via the identical newObfChain grammar).
  34. I1 string `json:"i1,omitempty"`
  35. I2 string `json:"i2,omitempty"`
  36. I3 string `json:"i3,omitempty"`
  37. I4 string `json:"i4,omitempty"`
  38. I5 string `json:"i5,omitempty"`
  39. // HeaderProtectionKey is a base64 32-byte key shared by both ends; the
  40. // ranges/booleans below are 3.x-only and optional.
  41. HeaderProtectionKey string `json:"headerProtectionKey,omitempty"`
  42. ContentPaddingAddition string `json:"contentPaddingAddition,omitempty"`
  43. RekeyAfterTime string `json:"rekeyAfterTime,omitempty"`
  44. RekeyTimeout string `json:"rekeyTimeout,omitempty"`
  45. RejectAfterTime string `json:"rejectAfterTime,omitempty"`
  46. KeepaliveTimeout string `json:"keepaliveTimeout,omitempty"`
  47. MaxHandshakeAttempts string `json:"maxHandshakeAttempts,omitempty"`
  48. RandomTrailers bool `json:"randomTrailers,omitempty"`
  49. DisableCookies bool `json:"disableCookies,omitempty"`
  50. }
  51. // Peer is one desired AmneziaWG peer: a client device the interface accepts.
  52. // Email attributes traffic and online status back to the owning client, the
  53. // same role SecretEntry.Name plays for mtproto.
  54. type Peer struct {
  55. Email string
  56. PublicKey string
  57. PresharedKey string
  58. AllowedIPs []string
  59. // ForwardedPorts is a raw, user-supplied port list ("80, 443, 8000-8100")
  60. // forwarded to this peer's tunnel address by internal/amneziawgnet's
  61. // PortForwardSet listener supervisor. Empty means no port-forwarding.
  62. ForwardedPorts string
  63. }
  64. // Instance is the desired runtime configuration of one AmneziaWG inbound: a
  65. // single interface (e.g. awg1) with a set of peers, mirroring how one mtproto
  66. // inbound maps to one mtg process (internal/mtproto.Instance).
  67. type Instance struct {
  68. Id int
  69. Tag string
  70. InterfaceName string
  71. ListenPort int
  72. // Listen is an optional host bind address (e.g. "203.0.113.10").
  73. // Empty/wildcard keeps dual-stack StdNetBind; a real IP pins the UDP socket.
  74. Listen string
  75. PrivateKey string
  76. PublicKey string
  77. // Address holds the interface's own tunnel address(es), e.g. "10.8.1.1/24".
  78. // Carries both the IPv4 and (when enabled) IPv6 server address.
  79. Address []string
  80. MTU int
  81. // Obfuscation carries the full AmneziaWG 3.1 parameter set, including
  82. // the 3.x header-protection/content-padding/timing/boolean fields (see
  83. // Obfuscation31's own doc comment) -- amneziawgnet.DeviceOptions is
  84. // what actually consumes it when building the embedded Device's UAPI
  85. // config.
  86. Obfuscation Obfuscation31
  87. Peers []Peer
  88. // ExternalInterface named the host NIC PostUp/PostDown NAT rules
  89. // attached to under the retired kernel-module architecture. Also the
  90. // fallback host NIC internal/amneziawgnet's IPv6-address-alias
  91. // mechanism (desiredV6Aliases) uses when IPv6ExternalInterface is left
  92. // blank.
  93. ExternalInterface string
  94. // IPv6Enabled/IPv6ExternalInterface gate internal/amneziawgnet's
  95. // IPv6-address-alias mechanism (desiredV6Aliases,
  96. // internal/web/service/xray.go's injectAmneziawgV6Egress): each peer
  97. // with an IPv6 AllowedIPs entry gets that address aliased onto this
  98. // host NIC (ip -6 addr add) and a dedicated Xray freedom outbound bound
  99. // to it, giving that peer's own outbound connections a distinct public
  100. // source identity. Narrower in scope than these identically-named
  101. // fields' role under the retired kernel-module architecture, which used
  102. // per-peer NDP-proxy entries (ip -6 neigh add proxy) to also support
  103. // unsolicited inbound connections toward the peer -- that capability is
  104. // the separate, not-yet-built Phase 3.6 (port-forwarding).
  105. IPv6Enabled bool
  106. IPv6ExternalInterface string
  107. // RouteThroughXray gated the kernel-module architecture's opt-in
  108. // TPROXY-into-Xray bridge. The embedded path (internal/amneziawgnet)
  109. // has no equivalent opt-in at all -- every peer's traffic already goes
  110. // through Xray's own SOCKS5 inbound unconditionally, since there's no
  111. // other way for decapsulated gVisor traffic to reach the real internet
  112. // -- so this field is now vestigial: read from existing stored settings
  113. // for backward compatibility, but not acted on by anything. Slated for
  114. // removal alongside the frontend toggle in a follow-up.
  115. RouteThroughXray bool
  116. }
  117. // ServerSettings is the "server" block of an AmneziaWG inbound's Settings
  118. // JSON: the interface-level configuration shared by every client/peer. The
  119. // listen port is deliberately not duplicated here — it lives on the inbound
  120. // row itself (Inbound.Port), like every other protocol.
  121. type ServerSettings struct {
  122. PrivateKey string `json:"privateKey"`
  123. PublicKey string `json:"publicKey"`
  124. SubnetIP string `json:"subnetIp"`
  125. SubnetCIDR int `json:"subnetCidr"`
  126. MTU int `json:"mtu,omitempty"`
  127. // PrimaryDNS/SecondaryDNS seed client configs' DNS line. Blank is
  128. // meaningful, so no omitempty: a dropped key resurrects frontend defaults.
  129. PrimaryDNS string `json:"primaryDns"`
  130. SecondaryDNS string `json:"secondaryDns"`
  131. // ExternalInterface, IPv6Enabled, and IPv6ExternalInterface are live
  132. // again as of Phase 3.5 -- see the matching fields on Instance for what
  133. // they gate (internal/amneziawgnet's IPv6-address-alias mechanism).
  134. // IPv6Subnet was never actually vestigial either: InstanceFromInbound
  135. // already consumes it (via serverAddressV6) to build the server's own
  136. // tunnel address, same as always. Only RouteThroughXray, below, remains
  137. // genuinely vestigial as of the hard cutover to the embedded path
  138. // (internal/amneziawgnet) -- read from existing stored settings for
  139. // backward compatibility, but not acted on by anything.
  140. ExternalInterface string `json:"externalInterface,omitempty"`
  141. IPv6Enabled bool `json:"ipv6Enabled,omitempty"`
  142. IPv6Subnet string `json:"ipv6Subnet,omitempty"`
  143. IPv6ExternalInterface string `json:"ipv6ExternalInterface,omitempty"`
  144. RouteThroughXray bool `json:"routeThroughXray,omitempty"`
  145. // Obfuscation31's fields, repeated flat (not embedded) rather than
  146. // nested under their own key: encoding/json would happily inline an
  147. // embedded Obfuscation31 the same way, but the frontend's Go->Zod/TS
  148. // generator (tools/openapigen) does not — it emits a genuinely nested
  149. // `obfuscation31` object, which would silently diverge from the real
  150. // wire JSON. See Obfuscation() below for the manager-facing conversion.
  151. Jc int `json:"jc"`
  152. Jmin int `json:"jmin"`
  153. Jmax int `json:"jmax"`
  154. S1 int `json:"s1"`
  155. S2 int `json:"s2"`
  156. S3 int `json:"s3"`
  157. S4 int `json:"s4"`
  158. H1 string `json:"h1"`
  159. H2 string `json:"h2"`
  160. H3 string `json:"h3"`
  161. H4 string `json:"h4"`
  162. I1 string `json:"i1,omitempty"`
  163. I2 string `json:"i2,omitempty"`
  164. I3 string `json:"i3,omitempty"`
  165. I4 string `json:"i4,omitempty"`
  166. I5 string `json:"i5,omitempty"`
  167. // HeaderProtectionKey and ContentPaddingAddition are AmneziaWG 3.0
  168. // fields, flat and top-level for the same tools/openapigen reason as
  169. // the block above; Obfuscation() below folds them back into
  170. // Obfuscation31's own identically named fields.
  171. // HeaderProtectionKey is a base64 32-byte key; empty (the default)
  172. // disables AWG 3.0 header protection. A non-empty value requires
  173. // every one of S1-S4 above to be >= 12 -- ValidateObfuscation
  174. // enforces this at save time, not just at IpcSet time.
  175. // ContentPaddingAddition is a "low-high" range or bare integer, the
  176. // same grammar and uint32 cap as H1-H4.
  177. HeaderProtectionKey string `json:"headerProtectionKey,omitempty"`
  178. ContentPaddingAddition string `json:"contentPaddingAddition,omitempty"`
  179. // RekeyAfterTime/RekeyTimeout/RejectAfterTime/KeepaliveTimeout/
  180. // MaxHandshakeAttempts mirror Instance's identically named fields --
  181. // see that type's own doc comment for the grammar/width/real-default
  182. // details. Flat and top-level for the same tools/openapigen reason as
  183. // the rest of this struct.
  184. RekeyAfterTime string `json:"rekeyAfterTime,omitempty"`
  185. RekeyTimeout string `json:"rekeyTimeout,omitempty"`
  186. RejectAfterTime string `json:"rejectAfterTime,omitempty"`
  187. KeepaliveTimeout string `json:"keepaliveTimeout,omitempty"`
  188. MaxHandshakeAttempts string `json:"maxHandshakeAttempts,omitempty"`
  189. // RandomTrailers/DisableCookies mirror Instance's identically named
  190. // AmneziaWG 3.1 fields -- see that type's own doc comment for the real
  191. // protocol/interop details. Both real bool fields (not omitempty):
  192. // buildUAPIConfig always emits both lines explicitly so the
  193. // reconfigure-in-place diff correctly notices a true->false edit, not
  194. // just false->true.
  195. RandomTrailers bool `json:"randomTrailers"`
  196. DisableCookies bool `json:"disableCookies"`
  197. }
  198. // Obfuscation extracts the Obfuscation31 parameter set from a ServerSettings
  199. // block, for callers (the Manager, ValidateObfuscation) that want the
  200. // grouped type rather than the flat wire fields.
  201. func (s ServerSettings) Obfuscation() Obfuscation31 {
  202. return Obfuscation31{
  203. Jc: s.Jc, Jmin: s.Jmin, Jmax: s.Jmax,
  204. S1: s.S1, S2: s.S2, S3: s.S3, S4: s.S4,
  205. H1: s.H1, H2: s.H2, H3: s.H3, H4: s.H4,
  206. I1: s.I1, I2: s.I2, I3: s.I3, I4: s.I4, I5: s.I5,
  207. HeaderProtectionKey: s.HeaderProtectionKey,
  208. ContentPaddingAddition: s.ContentPaddingAddition,
  209. RekeyAfterTime: s.RekeyAfterTime,
  210. RekeyTimeout: s.RekeyTimeout,
  211. RejectAfterTime: s.RejectAfterTime,
  212. KeepaliveTimeout: s.KeepaliveTimeout,
  213. MaxHandshakeAttempts: s.MaxHandshakeAttempts,
  214. RandomTrailers: s.RandomTrailers,
  215. DisableCookies: s.DisableCookies,
  216. }
  217. }
  218. // InboundSettings is the full Settings JSON shape stored on an AmneziaWG
  219. // inbound row: one server block plus the usual generic client list, so bulk
  220. // operations, the QR modal and subscriptions all come from the same shared
  221. // infrastructure every other protocol uses.
  222. type InboundSettings struct {
  223. Server *ServerSettings `json:"server"`
  224. Clients []model.Client `json:"clients"`
  225. }