@@ -70,13 +70,47 @@ func provisionSecurity(in *domain.Inbound) {
7070// InboundService manages inbounds and reconciles the owning node's live config
7171// after every change via the SyncService.
7272type InboundService struct {
73- repo port.InboundRepository
74- sync * SyncService
73+ repo port.InboundRepository
74+ nodes port.NodeRepository
75+ sync * SyncService
7576}
7677
7778// NewInboundService wires the service.
78- func NewInboundService (repo port.InboundRepository , sync * SyncService ) * InboundService {
79- return & InboundService {repo : repo , sync : sync }
79+ func NewInboundService (repo port.InboundRepository , nodes port.NodeRepository , sync * SyncService ) * InboundService {
80+ return & InboundService {repo : repo , nodes : nodes , sync : sync }
81+ }
82+
83+ // coreSupports reports whether the given core can run this protocol+network,
84+ // returning a clear error describing the incompatibility (or nil if supported).
85+ func coreSupports (core domain.CoreType , proto domain.Protocol , network string ) error {
86+ if network == "" {
87+ network = "tcp"
88+ }
89+ xrayProtos := map [domain.Protocol ]bool {domain .ProtoVMess : true , domain .ProtoVLESS : true , domain .ProtoTrojan : true , domain .ProtoShadowsocks : true }
90+ sbProtos := map [domain.Protocol ]bool {domain .ProtoVMess : true , domain .ProtoVLESS : true , domain .ProtoTrojan : true , domain .ProtoShadowsocks : true , domain .ProtoHysteria2 : true , domain .ProtoTUIC : true }
91+ xrayNets := map [string ]bool {"tcp" : true , "ws" : true , "grpc" : true , "httpupgrade" : true , "http" : true , "h2" : true , "xhttp" : true }
92+ sbNets := map [string ]bool {"tcp" : true , "ws" : true , "grpc" : true , "httpupgrade" : true , "http" : true , "h2" : true }
93+
94+ if proto == domain .ProtoWireGuard {
95+ return fmt .Errorf ("protocol %q is not supported as an inbound on any core" , proto )
96+ }
97+ switch core {
98+ case domain .CoreSingbox :
99+ if ! sbProtos [proto ] {
100+ return fmt .Errorf ("protocol %q is not supported on the sing-box core" , proto )
101+ }
102+ if ! sbNets [network ] {
103+ return fmt .Errorf ("transport %q is not supported on the sing-box core" , network )
104+ }
105+ default : // xray (and unspecified)
106+ if ! xrayProtos [proto ] {
107+ return fmt .Errorf ("protocol %q is not supported on the xray core (use a sing-box node)" , proto )
108+ }
109+ if ! xrayNets [network ] {
110+ return fmt .Errorf ("transport %q is not supported on the xray core" , network )
111+ }
112+ }
113+ return nil
80114}
81115
82116// CreateInboundInput describes a new inbound.
@@ -103,6 +137,13 @@ func (s *InboundService) Create(ctx context.Context, in CreateInboundInput) (*do
103137 if in .Tag == "" || in .Port == 0 {
104138 return nil , errors .New ("tag and port are required" )
105139 }
140+ node , err := s .nodes .GetByID (ctx , in .NodeID )
141+ if err != nil {
142+ return nil , errors .New ("node not found" )
143+ }
144+ if err := coreSupports (node .Core , in .Protocol , orStr (in .Network , "tcp" )); err != nil {
145+ return nil , err
146+ }
106147 inbound := & domain.Inbound {
107148 ID : uuid .New (),
108149 NodeID : in .NodeID ,
@@ -161,6 +202,13 @@ func (s *InboundService) Update(ctx context.Context, id uuid.UUID, in UpdateInbo
161202 if err != nil {
162203 return nil , err
163204 }
205+ node , err := s .nodes .GetByID (ctx , existing .NodeID )
206+ if err != nil {
207+ return nil , errors .New ("node not found" )
208+ }
209+ if err := coreSupports (node .Core , existing .Protocol , orStr (in .Network , "tcp" )); err != nil {
210+ return nil , err
211+ }
164212 existing .Listen = in .Listen
165213 existing .Port = in .Port
166214 existing .Network = orStr (in .Network , "tcp" )
0 commit comments