github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/cmd/geph-binder/bridges.go (about) 1 package main 2 3 import ( 4 "crypto/sha256" 5 "encoding/binary" 6 "encoding/hex" 7 "encoding/json" 8 "fmt" 9 "log" 10 "math/rand" 11 "net" 12 "net/http" 13 "strings" 14 "time" 15 16 "github.com/ethereum/go-ethereum/rlp" 17 "github.com/geph-official/geph2/libs/cshirt2" 18 "github.com/patrickmn/go-cache" 19 ) 20 21 // cache of all bridge info. string => bridgeInfo 22 var bridgeCache = cache.New(time.Minute*2, time.Minute) 23 24 type bridgeInfo struct { 25 Cookie []byte 26 Host string 27 LastSeen time.Time 28 AllocGroup string 29 } 30 31 func addBridge(nfo bridgeInfo) { 32 bridgeCache.SetDefault(string(nfo.Cookie), nfo) 33 } 34 35 // cache of bridge *mappings*. string => []string 36 var bridgeMapCache = cache.New(time.Hour, time.Hour) 37 38 func getBridges(id string) []string { 39 if mapping, ok := bridgeMapCache.Get(id); ok { 40 return mapping.([]string) 41 } 42 itms := bridgeCache.Items() 43 seed := fmt.Sprintf("%v-%v", id, time.Now()) 44 probability := 10.0 / float64(len(itms)) 45 candidates := make([][]string, 10) 46 candidateWeights := make([]int, 10) 47 // try 10 times 48 for i := 0; i < 10; i++ { 49 for k := range itms { 50 h := sha256.Sum256([]byte(k + seed)) 51 num := binary.BigEndian.Uint32(h[:4]) 52 if float64(num) < probability*float64(4294967295) || true { 53 candidates[i] = append(candidates[i], k) 54 } 55 //TODO diversity 56 candidateWeights[i] = len(candidates[i]) 57 } 58 } 59 var toret []string 60 trweight := -1 61 for i := 0; i < 10; i++ { 62 if candidateWeights[i] > trweight { 63 trweight = candidateWeights[i] 64 toret = candidates[i] 65 } 66 } 67 // shuffle 68 rand.Shuffle(len(toret), func(i, j int) { 69 toret[i], toret[j] = toret[j], toret[i] 70 }) 71 bridgeMapCache.SetDefault(id, toret) 72 return toret 73 } 74 75 func handleGetWarpfronts(w http.ResponseWriter, r *http.Request) { 76 countUserAgent(r) 77 host2front, err := getWarpfronts() 78 if err != nil { 79 w.WriteHeader(http.StatusInternalServerError) 80 return 81 } 82 w.Header().Set("content-type", "application/json") 83 json.NewEncoder(w).Encode(host2front) 84 } 85 86 var counterCache = cache.New(time.Minute, time.Hour) 87 88 func handleGetBridges(w http.ResponseWriter, r *http.Request) { 89 countUserAgent(r) 90 id := strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0] 91 // result, _ := goodIPCache.Get(id) 92 // if result == nil { 93 // log.Println("BAD IP:", id) 94 // w.WriteHeader(http.StatusForbidden) 95 // return 96 // } 97 // id = fmt.Sprintf("%v", result) 98 // fmt.Println("good IP with id", id) 99 100 isEphemeral := r.FormValue("type") == "ephemeral" 101 if isEphemeral { 102 w.WriteHeader(http.StatusBadRequest) 103 return 104 } 105 // TODO validate the ticket 106 bridges := getBridges(id) 107 w.Header().Set("content-type", "application/json") 108 idhash := sha256.Sum256([]byte(id)) 109 w.Header().Set("X-Requestor-ID", hex.EncodeToString(idhash[:])) 110 seenAGs := make(map[string]bool) 111 var laboo []bridgeInfo 112 vacate := func() { 113 bridgeMapCache.Delete(id) 114 } 115 for _, str := range bridges { 116 vali, ok := bridgeCache.Get(str) 117 if ok { 118 val := vali.(bridgeInfo) 119 if !seenAGs[val.AllocGroup] { 120 seenAGs[val.AllocGroup] = true 121 hostPort := strings.Split(val.Host, ":") 122 if len(hostPort) == 2 { 123 val.Host = fmt.Sprintf("%v.sslip.io:%v", strings.Replace(hostPort[0], ".", "-", -1), hostPort[1]) 124 laboo = append(laboo, val) 125 } 126 } 127 } else { 128 vacate() 129 return 130 } 131 } 132 if len(laboo) == 0 { 133 vacate() 134 return 135 } 136 json.NewEncoder(w).Encode(laboo) 137 } 138 139 func handleAddBridge(w http.ResponseWriter, r *http.Request) { 140 countUserAgent(r) 141 // first get the cookie 142 cookie, err := hex.DecodeString(r.FormValue("cookie")) 143 if err != nil { 144 log.Println("can't add bridge (bad cookie)") 145 w.WriteHeader(http.StatusInternalServerError) 146 return 147 } 148 // check the cookie 149 _, pwd, _ := r.BasicAuth() 150 ok, err := checkBridgeKey(pwd) 151 if err != nil { 152 log.Println("can't add bridge (bad DB)") 153 w.WriteHeader(http.StatusInternalServerError) 154 return 155 } 156 if !ok { 157 log.Printf("can't add bridge (bad bridge key %v)", pwd) 158 w.WriteHeader(http.StatusForbidden) 159 return 160 } 161 bi := bridgeInfo{ 162 Cookie: cookie, 163 Host: r.FormValue("host"), 164 LastSeen: time.Now(), 165 AllocGroup: r.FormValue("allocGroup"), 166 } 167 // add the bridge 168 addBridge(bi) 169 } 170 171 func testBridge(bi bridgeInfo) bool { 172 rawconn, err := net.Dial("tcp", bi.Host) 173 if err != nil { 174 log.Println("bridge test failed for", bi.Host, err) 175 return false 176 } 177 defer rawconn.Close() 178 realconn, err := cshirt2.ClientLegacy(bi.Cookie, rawconn) 179 if err != nil { 180 log.Println("bridge test failed for", bi.Host, err) 181 return false 182 } 183 defer realconn.Close() 184 realconn.SetDeadline(time.Now().Add(time.Second * 10)) 185 start := time.Now() 186 rlp.Encode(realconn, "ping") 187 var resp string 188 rlp.Decode(realconn, &resp) 189 if resp != "ping" { 190 log.Println(bi.Host, "failed ping test!") 191 return false 192 } 193 log.Println(bi.Host, "passed ping test in", time.Since(start)) 194 return true 195 }