@@ -44,7 +44,7 @@ type links struct {
4444
4545type linkProtocol interface {
4646 dial (ctx context.Context , url * url.URL , info linkInfo , options linkOptions ) (net.Conn , error )
47- listen (ctx context.Context , url * url.URL , sintf string ) (net.Listener , error )
47+ listen (ctx context.Context , url * url.URL , sintf string , options linkOptions ) (net.Listener , error )
4848}
4949
5050// linkInfo is used as a map key
@@ -72,6 +72,7 @@ type linkOptions struct {
7272 tlsSNI string
7373 password []byte
7474 maxBackoff time.Duration
75+ multipath bool
7576}
7677
7778type Listener struct {
@@ -140,6 +141,7 @@ const ErrLinkPinnedKeyInvalid = linkError("pinned public key is invalid")
140141const ErrLinkPasswordInvalid = linkError ("password is invalid" )
141142const ErrLinkUnrecognisedSchema = linkError ("link schema unknown" )
142143const ErrLinkMaxBackoffInvalid = linkError ("max backoff duration invalid" )
144+ const ErrLinkMultipathInvalid = linkError ("multipath invalid" )
143145
144146func (l * links ) add (u * url.URL , sintf string , linkType linkType ) error {
145147 var retErr error
@@ -193,6 +195,17 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
193195 }
194196 options .maxBackoff = d
195197 }
198+ if p := u .Query ().Get ("multipath" ); p != "" {
199+ switch p {
200+ case "true" , "1" :
201+ options .multipath = true
202+ case "false" , "0" :
203+ options .multipath = false
204+ default :
205+ retErr = ErrLinkMultipathInvalid
206+ return
207+ }
208+ }
196209 // SNI headers must contain hostnames and not IP addresses, so we must make sure
197210 // that we do not populate the SNI with an IP literal. We do this by splitting
198211 // the host-port combo from the query option and then seeing if it parses to an
@@ -379,7 +392,7 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
379392 return retErr
380393}
381394
382- func (l * links ) remove (u * url.URL , sintf string , linkType linkType ) error {
395+ func (l * links ) remove (u * url.URL , sintf string , _ linkType ) error {
383396 var retErr error
384397 phony .Block (l , func () {
385398 // Generate the link info and see whether we think we already
@@ -422,31 +435,45 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
422435 cancel ()
423436 return nil , ErrLinkUnrecognisedSchema
424437 }
425- listener , err := protocol .listen (ctx , u , sintf )
426- if err != nil {
427- cancel ()
428- return nil , err
429- }
430- li := & Listener {
431- listener : listener ,
432- ctx : ctx ,
433- Cancel : cancel ,
434- }
435438
436439 var options linkOptions
437440 if p := u .Query ().Get ("priority" ); p != "" {
438441 pi , err := strconv .ParseUint (p , 10 , 8 )
439442 if err != nil {
443+ cancel ()
440444 return nil , ErrLinkPriorityInvalid
441445 }
442446 options .priority = uint8 (pi )
443447 }
444448 if p := u .Query ().Get ("password" ); p != "" {
445449 if len (p ) > blake2b .Size {
450+ cancel ()
446451 return nil , ErrLinkPasswordInvalid
447452 }
448453 options .password = []byte (p )
449454 }
455+ if p := u .Query ().Get ("multipath" ); p != "" {
456+ switch p {
457+ case "true" , "1" :
458+ options .multipath = true
459+ case "false" , "0" :
460+ options .multipath = false
461+ default :
462+ cancel ()
463+ return nil , ErrLinkMultipathInvalid
464+ }
465+ }
466+
467+ listener , err := protocol .listen (ctx , u , sintf , options )
468+ if err != nil {
469+ cancel ()
470+ return nil , err
471+ }
472+ li := & Listener {
473+ listener : listener ,
474+ ctx : ctx ,
475+ Cancel : cancel ,
476+ }
450477
451478 go func () {
452479 l .core .log .Infof ("%s listener started on %s" , strings .ToUpper (u .Scheme ), listener .Addr ())
@@ -567,7 +594,7 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s
567594 switch {
568595 case err != nil :
569596 return fmt .Errorf ("write handshake: %w" , err )
570- case err == nil && n != len (metaBytes ):
597+ case n != len (metaBytes ):
571598 return fmt .Errorf ("incomplete handshake send" )
572599 }
573600 meta = version_metadata {}
0 commit comments