99package clientcontext
1010
1111import (
12+ stdbufio "bufio"
13+ "bytes"
1214 "context"
1315 "encoding/json"
1416 "fmt"
17+ "io"
1518 "net"
19+ "net/http"
1620
1721 "github.com/sagernet/sing-box/adapter"
1822 "github.com/sagernet/sing-box/log"
1923 "github.com/sagernet/sing/common/buf"
24+ "github.com/sagernet/sing/common/bufio"
25+ "github.com/sagernet/sing/common/metadata"
2026 N "github.com/sagernet/sing/common/network"
2127 "github.com/sagernet/sing/service"
2228)
@@ -161,36 +167,68 @@ func (b *boundsRule) match(tag string) bool {
161167type readConn struct {
162168 net.Conn
163169 ctx context.Context
164- info * ClientInfo
170+ info ClientInfo
165171 logger log.ContextLogger
172+
173+ reader io.Reader
174+ n int
175+ readErr error
166176}
167177
168178// newReadConn creates a readConn and reads client info from it. If successful, the info is stored
169179// in the context.
170180func newReadConn (ctx context.Context , conn net.Conn , logger log.ContextLogger ) net.Conn {
171- c := & readConn {Conn : conn , ctx : ctx }
172- info , err := c .readInfo ()
173- if err != nil {
174- logger .Error ("reading client info " , err )
175- return conn
181+ c := & readConn {
182+ Conn : conn ,
183+ ctx : ctx ,
184+ reader : conn ,
185+ logger : logger ,
186+ }
187+ if err := c .readInfo (); err != nil {
188+ logger .Warn ("reading client info: " , err )
176189 }
177- service .ContextWithPtr (ctx , info )
178190 return c
179191}
180192
181- // readInfo reads and decodes client info, then sends an OK response.
182- func (c * readConn ) readInfo () (* ClientInfo , error ) {
193+ func (c * readConn ) Read (b []byte ) (n int , err error ) {
194+ if c .readErr != nil {
195+ return c .n , c .readErr
196+ }
197+ return c .reader .Read (b )
198+ }
199+
200+ // readInfo reads and decodes client info, then sends an HTTP 200 OK response.
201+ func (c * readConn ) readInfo () error {
202+ var buf [32 ]byte
203+ n , err := c .Conn .Read (buf [:])
204+ if err != nil {
205+ c .readErr = err
206+ c .n = n
207+ return err
208+ }
209+ reader := io .MultiReader (bytes .NewReader (buf [:n ]), c .Conn )
210+ if ! bytes .HasPrefix (buf [:n ], []byte ("POST /clientinfo" )) {
211+ c .reader = reader
212+ return nil
213+ }
214+
183215 var info ClientInfo
184- if err := json .NewDecoder (c ).Decode (& info ); err != nil {
185- return nil , fmt .Errorf ("decoding client info: %w" , err )
216+ req , err := http .ReadRequest (stdbufio .NewReader (reader ))
217+ if err != nil {
218+ return fmt .Errorf ("reading HTTP request: %w" , err )
186219 }
187- c .info = & info
220+ defer req .Body .Close ()
221+ if err := json .NewDecoder (req .Body ).Decode (& info ); err != nil {
222+ return fmt .Errorf ("decoding client info: %w" , err )
223+ }
224+ c .info = info
188225
189- // send `OK` response
190- if _ , err := c .Write ([]byte ("OK" )); err != nil {
191- return nil , fmt .Errorf ("writing OK response to client : %w" , err )
226+ resp := "HTTP/1.1 200 OK \r \n Content-Length: 0 \r \n \r \n "
227+ if _ , err := c .Write ([]byte (resp )); err != nil {
228+ return fmt .Errorf ("writing HTTP response: %w" , err )
192229 }
193- return & info , nil
230+ service .ContextWithPtr (c .ctx , & info )
231+ return nil
194232}
195233
196234// writeConn sends client info after handshake.
@@ -213,70 +251,101 @@ func (c *writeConn) ConnHandshakeSuccess(conn net.Conn) error {
213251 return nil
214252}
215253
216- // sendInfo marshals and sends client info, then waits for OK.
254+ // sendInfo marshals and sends client info as an HTTP POST , then waits for HTTP 200 OK.
217255func (c * writeConn ) sendInfo (conn net.Conn ) error {
218256 buf , err := json .Marshal (c .info )
219257 if err != nil {
220258 return fmt .Errorf ("marshaling client info: %w" , err )
221259 }
222- if _ , err = conn .Write (buf ); err != nil {
260+ // Write HTTP POST request
261+ req := bytes .NewBuffer (nil )
262+ fmt .Fprintf (req , "POST /clientinfo HTTP/1.1\r \n " )
263+ fmt .Fprintf (req , "Host: localhost\r \n " )
264+ fmt .Fprintf (req , "Content-Type: application/json\r \n " )
265+ fmt .Fprintf (req , "Content-Length: %d\r \n " , len (buf ))
266+ fmt .Fprintf (req , "\r \n " )
267+ req .Write (buf )
268+ if _ , err = conn .Write (req .Bytes ()); err != nil {
223269 return fmt .Errorf ("writing client info: %w" , err )
224270 }
225271
226- // wait for `OK` response
227- resp := make ([]byte , 2 )
228- if _ , err := conn .Read (resp ); err != nil {
229- return fmt .Errorf ("reading server response: %w" , err )
272+ // wait for HTTP 200 OK response
273+ reader := stdbufio .NewReader (conn )
274+ resp , err := http .ReadResponse (reader , nil )
275+ if err != nil {
276+ return fmt .Errorf ("reading HTTP response: %w" , err )
230277 }
231- if string (resp ) != "OK" {
232- return fmt .Errorf ("invalid server response: %s" , resp )
278+ defer resp .Body .Close ()
279+ if resp .StatusCode != 200 {
280+ return fmt .Errorf ("invalid server response: %s" , resp .Status )
233281 }
234282 return nil
235283}
236284
285+ const prefix = "CLIENTINFO "
286+
237287type readPacketConn struct {
238288 N.PacketConn
239289 ctx context.Context
240290 info * ClientInfo
241291 logger log.ContextLogger
292+
293+ reader io.Reader
294+ destination metadata.Socksaddr
295+ readErr error
242296}
243297
244298// newReadPacketConn creates a readPacketConn and reads client info from it. If successful, the
245299// info is stored in the context.
246300func newReadPacketConn (ctx context.Context , conn N.PacketConn , logger log.ContextLogger ) N.PacketConn {
247- c := & readPacketConn {PacketConn : conn , ctx : ctx , logger : logger }
248- info , err := c .readInfo ()
249- if err != nil {
250- logger .Error ("reading client info " , err )
251- return conn
301+ c := & readPacketConn {
302+ PacketConn : conn ,
303+ ctx : ctx ,
304+ logger : logger ,
305+ }
306+ if err := c .readInfo (); err != nil {
307+ logger .Warn ("reading client info: " , err )
252308 }
253-
254- service .ContextWithPtr (ctx , info )
255309 return c
256310}
257311
258- // readInfo reads and decodes client info, then sends an OK response.
259- func (c * readPacketConn ) readInfo () (* ClientInfo , error ) {
312+ func (c * readPacketConn ) ReadPacket (b * buf.Buffer ) (destination metadata.Socksaddr , err error ) {
313+ if c .readErr != nil {
314+ return c .destination , c .readErr
315+ }
316+ return c .PacketConn .ReadPacket (b )
317+ }
318+
319+ // readInfo reads and decodes client info if the first packet is a CLIENTINFO packet, then sends an
320+ // OK response.
321+ func (c * readPacketConn ) readInfo () error {
260322 buffer := buf .NewPacket ()
261323 defer buffer .Release ()
262324
263325 destination , err := c .ReadPacket (buffer )
264326 if err != nil {
265- return nil , fmt .Errorf ("reading packet from client: %w" , err )
327+ c .readErr = err
328+ return err
329+ }
330+ data := buffer .Bytes ()
331+ if ! bytes .HasPrefix (data , []byte (prefix )) {
332+ // not a client info packet, wrap with cached packet conn so the packet can be read again
333+ c .PacketConn = bufio .NewCachedPacketConn (c .PacketConn , buffer , destination )
334+ return nil
266335 }
267336 var info ClientInfo
268- if err := json .Unmarshal (buffer . Bytes () , & info ); err != nil {
269- return nil , fmt .Errorf ("decoding client info: %w" , err )
337+ if err := json .Unmarshal (data [ len ( prefix ):] , & info ); err != nil {
338+ return fmt .Errorf ("unmarshaling client info: %w" , err )
270339 }
271340 c .info = & info
272341
273- // send `OK` response
274342 buffer .Reset ()
275343 buffer .WriteString ("OK" )
276344 if err := c .WritePacket (buffer , destination ); err != nil {
277- return nil , fmt .Errorf ("writing OK response to client : %w" , err )
345+ return fmt .Errorf ("writing OK response: %w" , err )
278346 }
279- return & info , nil
347+ service .ContextWithPtr (c .ctx , & info )
348+ return nil
280349}
281350
282351type writePacketConn struct {
@@ -311,13 +380,14 @@ func (c *writePacketConn) PacketConnHandshakeSuccess(conn net.PacketConn) error
311380 return nil
312381}
313382
314- // sendInfo marshals and sends client info, then waits for OK.
383+ // sendInfo marshals and sends client info as a CLIENTINFO packet , then waits for OK.
315384func (c * writePacketConn ) sendInfo (conn net.PacketConn ) error {
316385 buf , err := json .Marshal (c .info )
317386 if err != nil {
318387 return fmt .Errorf ("marshaling client info: %w" , err )
319388 }
320- _ , err = conn .WriteTo (buf , c .metadata .Destination )
389+ packet := append ([]byte (prefix ), buf ... )
390+ _ , err = conn .WriteTo (packet , c .metadata .Destination )
321391 if err != nil {
322392 return fmt .Errorf ("writing packet: %w" , err )
323393 }
0 commit comments