github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/cmd/geph-client/getmux.go (about) 1 package main 2 3 import ( 4 "crypto/ed25519" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "math/rand" 9 "net" 10 "os" 11 "strings" 12 "sync" 13 "time" 14 15 log "github.com/sirupsen/logrus" 16 17 "github.com/ethereum/go-ethereum/rlp" 18 "github.com/geph-official/geph2/libs/bdclient" 19 "github.com/geph-official/geph2/libs/cshirt2" 20 "github.com/geph-official/geph2/libs/tinyss" 21 ) 22 23 func negotiateTinySS(greeting *[2][]byte, rawConn net.Conn, pk []byte, nextProto byte) (cryptConn *tinyss.Socket, err error) { 24 rawConn.SetDeadline(time.Now().Add(time.Second * 20)) 25 cryptConn, err = tinyss.Handshake(rawConn, nextProto) 26 if err != nil { 27 err = fmt.Errorf("tinyss handshake failed: %w", err) 28 rawConn.Close() 29 return 30 } 31 // verify the actual msg 32 var sssig []byte 33 err = rlp.Decode(cryptConn, &sssig) 34 if err != nil { 35 err = fmt.Errorf("cannot decode sssig: %w", err) 36 rawConn.Close() 37 return 38 } 39 if !ed25519.Verify(pk, cryptConn.SharedSec(), sssig) { 40 err = errors.New("man in the middle") 41 rawConn.Close() 42 return 43 } 44 if greeting != nil { 45 // send the greeting 46 rlp.Encode(cryptConn, greeting) 47 // wait for the reply 48 var reply string 49 err = rlp.Decode(cryptConn, &reply) 50 if err != nil { 51 err = fmt.Errorf("cannot decode reply: %w", err) 52 rawConn.Close() 53 return 54 } 55 if reply != "OK" { 56 err = errors.New("authentication failed") 57 rawConn.Close() 58 log.Println("authentication failed", reply) 59 os.Exit(11) 60 } 61 } 62 return 63 } 64 65 func dialBridge(host string, cookie []byte) (net.Conn, error) { 66 var port uint64 67 portrng := cshirt2.NewRNG(cookie) 68 for i := 0; i < rand.Int()%16+1; i++ { 69 port = portrng() % 65536 70 } 71 recombinedHost := fmt.Sprintf("%v:%v", strings.Split(host, ":")[0], port) 72 conn, err := net.DialTimeout("tcp", recombinedHost, time.Second*15) 73 if err != nil { 74 return nil, err 75 } 76 conn.(*net.TCPConn).SetKeepAlive(false) 77 return cshirt2.Client(cookie, conn) 78 } 79 80 var greetingCache struct { 81 ubmsg []byte 82 ubsig []byte 83 expires time.Time 84 lock sync.Mutex 85 } 86 87 func getGreeting() (ubmsg, ubsig []byte, err error) { 88 greetingCache.lock.Lock() 89 defer greetingCache.lock.Unlock() 90 if time.Now().Before(greetingCache.expires) { 91 ubmsg, ubsig = greetingCache.ubmsg, greetingCache.ubsig 92 return 93 } 94 // obtain a ticket 95 var ticket bdclient.TicketResp 96 err = binders.Do(func(b *bdclient.Client) error { 97 var err error 98 ubmsg, ubsig, ticket, err = b.GetTicket(username, password) 99 return err 100 }) 101 if err != nil { 102 log.Errorln("error authenticating:", err) 103 if errors.Is(err, bdclient.ErrBadAuth) && loginCheck { 104 os.Exit(11) 105 } 106 return 107 } 108 if loginCheck { 109 os.Exit(0) 110 } 111 useStats(func(sc *stats) { 112 sc.Username = username 113 sc.Expiry = ticket.PaidExpiry 114 sc.Tier = ticket.Tier 115 sc.PayTxes = ticket.Transactions 116 }) 117 greetingCache.ubmsg = ubmsg 118 greetingCache.ubsig = ubsig 119 greetingCache.expires = time.Now().Add(time.Second * 30) 120 return 121 } 122 123 var bridgesCache struct { 124 bridges []bdclient.BridgeInfo 125 expires time.Time 126 lock sync.Mutex 127 } 128 129 func getBridges(ubmsg, ubsig []byte) ([]bdclient.BridgeInfo, error) { 130 bridgesCache.lock.Lock() 131 defer bridgesCache.lock.Unlock() 132 if time.Now().Before(bridgesCache.expires) { 133 return bridgesCache.bridges, nil 134 } 135 var bridges []bdclient.BridgeInfo 136 e := binders.Do(func(b *bdclient.Client) error { 137 var err error 138 bridges, err = b.GetBridges(ubmsg, ubsig) 139 return err 140 }) 141 if e != nil { 142 return nil, e 143 } 144 if additionalBridges != "" { 145 relays := strings.Split(additionalBridges, ";") 146 for _, str := range relays { 147 splitted := strings.Split(str, "@") 148 if len(splitted) != 2 { 149 panic("-additionalBridges must be cookie1@host1:port1;cookie2@host2:port2 etc") 150 } 151 cookie, err := hex.DecodeString(splitted[0]) 152 if err != nil { 153 panic(err) 154 } 155 bridges = append(bridges, bdclient.BridgeInfo{Cookie: cookie, Host: splitted[1]}) 156 } 157 } 158 log.Infoln("Obtained", len(bridges), "bridges") 159 for _, b := range bridges { 160 log.Infof(".... %v %x", b.Host, b.Cookie) 161 } 162 bridgesCache.bridges, bridgesCache.expires = bridges, time.Now().Add(time.Minute) 163 return bridges, nil 164 }