mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-16 15:17:14 +00:00
feat(amneziawg): add native AmneziaWG protocol backend
AmneziaWG (WireGuard plus DPI-resistant obfuscation) needs no Docker here — it runs as a genuine kernel interface via awg-quick/awg, managed the same way internal/mtproto manages mtg: one Inbound row is one desired Instance, and a Manager reconciles running interfaces toward the database every 10s (internal/web/job/amneziawg_job.go) plus immediately after a client edit (applyLocalAmneziaWG). Clients reuse model.Client verbatim (the same PrivateKey/PublicKey/ PreSharedKey/AllowedIPs fields WireGuard already uses), so bulk operations, the QR/share-link modal and subscriptions come from the shared inbound infrastructure instead of a parallel implementation. internal/amneziawg owns the obfuscation param generator/validator (ported from coinman-dev/3ax-ui, upgraded to AmneziaWG 2.0's S3/S4 padding and I1 signature packet) and the exec wrapper around awg-quick/awg, with fingerprint-based reconcile (noop / reload-via- syncconf / full restart) mirroring mtproto.Manager so a same-protocol edit doesn't force an unnecessary interface bounce that would drop every peer's connection. Frontend and install.sh's DKMS/awg-tools setup are tracked separately; this is backend-only. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/mtproto"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -53,6 +54,13 @@ func (l *Local) AddInbound(_ context.Context, ib *model.Inbound) error {
|
||||
}
|
||||
return mtproto.GetManager().Ensure(inst)
|
||||
}
|
||||
if ib.Protocol == model.AmneziaWG {
|
||||
inst, ok := amneziawg.InstanceFromInbound(ib)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return amneziawg.GetManager().Ensure(inst)
|
||||
}
|
||||
body, err := json.MarshalIndent(ib.GenXrayInboundConfig(), "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -67,6 +75,10 @@ func (l *Local) DelInbound(_ context.Context, ib *model.Inbound) error {
|
||||
mtproto.GetManager().Remove(ib.Id)
|
||||
return nil
|
||||
}
|
||||
if ib.Protocol == model.AmneziaWG {
|
||||
amneziawg.GetManager().Remove(ib.Id)
|
||||
return nil
|
||||
}
|
||||
return l.withAPI(func(api *xray.XrayAPI) error {
|
||||
return api.DelInbound(ib.Tag)
|
||||
})
|
||||
@@ -76,6 +88,9 @@ func (l *Local) UpdateInbound(ctx context.Context, oldIb, newIb *model.Inbound)
|
||||
if oldIb.Protocol == model.MTProto || newIb.Protocol == model.MTProto {
|
||||
return l.updateMtprotoInbound(ctx, oldIb, newIb)
|
||||
}
|
||||
if oldIb.Protocol == model.AmneziaWG || newIb.Protocol == model.AmneziaWG {
|
||||
return l.updateAmneziaWGInbound(ctx, oldIb, newIb)
|
||||
}
|
||||
_ = l.DelInbound(ctx, oldIb)
|
||||
if !newIb.Enable {
|
||||
return nil
|
||||
@@ -112,8 +127,36 @@ func (l *Local) updateMtprotoInbound(ctx context.Context, oldIb, newIb *model.In
|
||||
return mtproto.GetManager().Ensure(inst)
|
||||
}
|
||||
|
||||
// updateAmneziaWGInbound mirrors updateMtprotoInbound: it skips the
|
||||
// Remove+Ensure sequence a plain Del+Add would force so that, on an
|
||||
// AmneziaWG-to-AmneziaWG edit, Manager.Ensure's own fingerprint comparison
|
||||
// can pick a peers-only `syncconf` instead of always bouncing the interface
|
||||
// (see internal/amneziawg.Manager.ensureLocked).
|
||||
func (l *Local) updateAmneziaWGInbound(ctx context.Context, oldIb, newIb *model.Inbound) error {
|
||||
if oldIb.Protocol == model.AmneziaWG && newIb.Protocol != model.AmneziaWG {
|
||||
amneziawg.GetManager().Remove(oldIb.Id)
|
||||
if !newIb.Enable {
|
||||
return nil
|
||||
}
|
||||
return l.AddInbound(ctx, newIb)
|
||||
}
|
||||
if oldIb.Protocol != model.AmneziaWG {
|
||||
_ = l.DelInbound(ctx, oldIb)
|
||||
}
|
||||
if !newIb.Enable {
|
||||
amneziawg.GetManager().Remove(newIb.Id)
|
||||
return nil
|
||||
}
|
||||
inst, ok := amneziawg.InstanceFromInbound(newIb)
|
||||
if !ok {
|
||||
amneziawg.GetManager().Remove(newIb.Id)
|
||||
return nil
|
||||
}
|
||||
return amneziawg.GetManager().Ensure(inst)
|
||||
}
|
||||
|
||||
func (l *Local) AddUser(_ context.Context, ib *model.Inbound, userMap map[string]any) error {
|
||||
if ib.Protocol == model.MTProto {
|
||||
if ib.Protocol == model.MTProto || ib.Protocol == model.AmneziaWG {
|
||||
return nil
|
||||
}
|
||||
return l.withAPI(func(api *xray.XrayAPI) error {
|
||||
@@ -122,7 +165,7 @@ func (l *Local) AddUser(_ context.Context, ib *model.Inbound, userMap map[string
|
||||
}
|
||||
|
||||
func (l *Local) RemoveUser(_ context.Context, ib *model.Inbound, email string) error {
|
||||
if ib.Protocol == model.MTProto {
|
||||
if ib.Protocol == model.MTProto || ib.Protocol == model.AmneziaWG {
|
||||
return nil
|
||||
}
|
||||
return l.withAPI(func(api *xray.XrayAPI) error {
|
||||
|
||||
Reference in New Issue
Block a user