//given an ID, searches the local store, DHT, and if found unmarshals the bytes into a MartiniContact func findMartiniContact(dm *DryMartini, hashedID kademlia.ID) (MartiniContact, bool) { var mcBytes []byte var mc MartiniContact var err error var success bool mcBytes, success = dm.KademliaInst.ValueStore.Get(hashedID) if !success { success, _, mcBytes, err = kademlia.IterativeFind(dm.KademliaInst, hashedID, 2) if err != nil { dbg.Printf("findingMartiniContact failed. searching for key:%s. err:%s\n", ERRORS, hashedID.AsString(), err) return mc, false } if success { dbg.Printf("findMartiniContact: foundValue\n", Verbose) } else { dbg.Printf("IterativeFind failed to findvalue for key:%s\n", ERRORS, hashedID.AsString()) return mc, false } } else { //dbg.Printf("found martiniContact locally. Key:%+v\n", hashedID) } err = json.Unmarshal(mcBytes, &mc) dbg.Printf("findMartiniContact: 'foundContact.NodeIP:%s, Port:%d\n", Verbose, mc.NodeIP, mc.NodePort) if err != nil { dbg.Printf("Error unmarshaling found MartiniContact. %s\n", ERRORS, err) panic(1) } return mc, true }
//decrypts encrypted data with pathKeys //pathKeys are in order of closest Nodes key to furthest func UnwrapOlivesForPath(dm *DryMartini, pathKeys []FlowIDSymmKeyPair, Data []byte) []byte { var err error var tempOlive Olive var decData []byte var theData []byte pathLength := len(pathKeys) theData = Data for i := 0; i < pathLength; i++ { //encrypt the Data (using furthest nodes key) and put it into tempOlive dbg.Printf("UnwrapOlivesForPath; (len(pathkey)=%d) (len(theData)=%d) decrypting USING SYMMKEY and FLOWID: %+v\n", Verbose, len(pathKeys), len(theData), pathKeys[i]) decData = DecryptDataSymm(theData, pathKeys[i].SymmKey) //marshal the temp Olive err = json.Unmarshal(decData, &tempOlive) if err != nil { dbg.Printf("error marshalling Olive:%+v, err:%s\n", ERRORS, tempOlive, err) panic(1) } theData = tempOlive.Data } return theData }
//stores dm's contactInfo in the DHT func StoreContactInfo(dm *DryMartini) { var err error var mcBytes []byte var key kademlia.ID = dm.KademliaInst.ContactInfo.NodeID.SHA1Hash() mcBytes, err = json.Marshal(dm.myMartiniContact) if err != nil { dbg.Printf("error marshalling MartiniContact: %s\n", true, err) } var m MartiniContact err = json.Unmarshal(mcBytes, &m) if err != nil { dbg.Printf("error: drymartini.PrintLocalData %s\n", (err != nil), err) } dbg.Printf("Print HashMap[%s]=%+v\n", Verbose, key.AsString(), m) dbg.Printf("storing martiniContact:%+v %+v at ID: %x\n", Verbose, dm.myMartiniContact, mcBytes, key) kademlia.MakeIterativeStore(dm.KademliaInst, key, mcBytes) go func() { //republish contact info ever 4 minutes. (expire time is hardcoded at 5minutes in kademlia.rpc) for { time.Sleep(time.Duration(4) * time.Minute) kademlia.MakeIterativeStore(dm.KademliaInst, key, mcBytes) } }() }
// Create a new DryMartini object with its own kademlia and RPC server func NewDryMartini(listenStr string, keylen int) *DryMartini { var err error var s *rpc.Server var dm *DryMartini dm = new(DryMartini) dm.EasyNewFlowIndex = 0 //Initialize key pair dm.KeyPair, err = rsa.GenerateKey(rand.Reader, keylen) if err != nil { dbg.Printf("Failed to generate key! %s", true, err) panic(1) } //Initialize flow struct dm.Bartender = make(map[UUID]MartiniPick) dm.Momento = make(map[UUID][]FlowIDSymmKeyPair) dm.MapFlowIndexToFlowID = make(map[int]FlowInfo) var host net.IP var port uint16 host, port, err = kademlia.AddrStrToHostPort(listenStr) //Initialize our Kademlia //portStr := strconv.FormatUint(uint64(port), 10) //var rpcPathStr string = kademlia.RpcPath+portStr var rpcPathStr = "junk" dbg.Printf("making new Kademlia with listenStr:%s, rpcPath\n", Verbose, listenStr, rpcPathStr) dm.KademliaInst, s = kademlia.NewKademlia(listenStr, &rpcPathStr) kademlia.BucketsAsArray(dm.KademliaInst) //myMartiniContact <- ip, port, public key dm.myMartiniContact.NodeIP = host.String() dm.myMartiniContact.NodePort = port dm.myMartiniContact.PubKey = dm.KeyPair.PublicKey.N.String() dm.myMartiniContact.PubExp = dm.KeyPair.PublicKey.E dbg.Printf("NewDryMartini: making new Kademlia with NodeIP: %s. NodePort:%d\n", Verbose, dm.myMartiniContact.NodeIP, dm.myMartiniContact.NodePort) /* if Verbose { dbg.Printf("NodeIP: %s\n", dm.myMartiniContact.NodeIP) dbg.Printf("NodePort: %d\n", dm.myMartiniContact.NodePort) dbg.Printf("PubKey: %s\n", dm.myMartiniContact.PubKey) dbg.Printf("PubExp: %d\n", dm.myMartiniContact.PubKey) }*/ //register err = s.Register(dm) if err != nil { dbg.Printf("Failed to register Drymartini! %s", true, err) panic(1) } return dm }
func FindGoodPath(dm *DryMartini) (bool, int) { dbg.Printf("FindGoodPath: FlowIndexToFlowID map:%+v\n", Verbose, dm.MapFlowIndexToFlowID) for index, flowInfo := range dm.MapFlowIndexToFlowID { if time.Now().Before(flowInfo.expireAt) { dbg.Printf("FindGoodPath: returning index:%d\n", Verbose, index) return true, index } } return false, -1 }
func PrintArrayOfFoundNodes(array *[]FoundNode) { dbg.Printf("Print Returned Found Nodes\n", Verbose) if len(*array) == 0 { return } for i, v := range *array { dbg.Printf("[%d] --> %s %s %d\n", Verbose, i, v.NodeID.AsString(), v.IPAddr, v.Port) } return }
func Printf(format string, k *Kademlia, doPrint bool, v ...interface{}) { if RunningTests { if v != nil { (k.log).Printf(format, v...) } else { (k.log).Printf(format) } } if v != nil { dbg.Printf(format, doPrint, v...) } else { dbg.Printf(format, doPrint) } }
func NewContact(AddrStr string) Contact { var err error var nodeID ID var host net.IP var port uint16 nodeID = NewRandomID() host, port, err = AddrStrToHostPort(AddrStr) if err != nil { dbg.Printf("NewContact: error parsing Address STring to host/port:%s\n", true, err) } dbg.Printf("Creating new contact %s %s\n", Verbose, nodeID.AsString(), AddrStr) return Contact{nodeID, host, port} }
func sendRPCsToFoundNodes(k *Kademlia, findType int, localContact *Contact, searchID ID, slist *list.List, sentMap map[ID]bool, liveMap map[ID]bool) ([]FoundNode, []byte) { //var value []byte //log.Printf("sendRPCsToFoundNodes: Start\n") dbg.Printf("sendRPCsToFoundNodes: shortlist:%+v\n", Verbose, *slist) for e := slist.Front(); e != nil; e = e.Next() { dbg.Printf("foundNode:%+v\n", Verbose, *(e.Value.(*FoundNode))) } resChan := make(chan *FindStarCallResponse, slist.Len()) var ret []FoundNode = make([]FoundNode, 0, slist.Len()) var rpcCount int = 0 var i int = 0 for e := slist.Front(); e != nil; e = e.Next() { foundNode := e.Value.(*FoundNode) remote := foundNode.FoundNodeToContact() if sentMap[foundNode.NodeID] { if liveMap[foundNode.NodeID] { ret = append(ret, *foundNode) } i++ continue } rpcCount++ if findType == 1 { //FindNode go MakeFindNodeCall(k, remote, searchID, resChan) } else if findType == 2 { //FindValue go MakeFindValueCall(k, remote, searchID, resChan) } } //pull replies out of the channel for ; rpcCount > 0; rpcCount-- { findNodeResult := <-resChan if findNodeResult.Responded { k.UpdateChannel <- *findNodeResult.Responder.FoundNodeToContact() if 2 == findType { if findNodeResult.ReturnedFVRes.Value != nil { var nArray []FoundNode = []FoundNode{*(findNodeResult.Responder)} return nArray, findNodeResult.ReturnedFVRes.Value } } dbg.Printf("adding 'live' responder to ret list:%+v\n", Verbose, *findNodeResult.Responder) ret = append(ret, *findNodeResult.Responder) i++ } } dbg.Printf("sendRPCsToFoundNodes returning:%+v\n", Verbose, ret) return ret, nil }
func MakeMartiniPing(dm *DryMartini, remoteHost net.IP, remotePort uint16) bool { dbg.Printf("MakeMartiniPing %s %d\n", Verbose, remoteHost, remotePort) //TODO: maybe should throw in a DoJoin(dm) here? return kademlia.MakePingCall(dm.KademliaInst, remoteHost, remotePort) }
func (k *Kademlia) FindValue(req FindValueRequest, res *FindValueResult) error { var err error var found bool //log.Printf("RPC:FindValue, from %s\n", req.Sender.NodeID.AsString()) // TODO: Implement. //search for the value //res.Value = data[req.Key] //var found bool //res.Value, found = k.HashMap[req.Key] //Updated code for store handler --> seems too verbose res.Value, found = k.ValueStore.Get(req.Key) if found { dbg.Printf("RPC:FindValue, found value [%s:%s]\n", Verbose, req.Key.AsString(), string(res.Value)) } else { res.Nodes, err = FindKClosest(k, req.Key, req.Sender.NodeID) } res.MsgID = CopyID(req.MsgID) //REVIEW: What kind of error can happen in this function? return err }
//Call Update on Contact whenever you communicate successfully func Update(k *Kademlia, triplet Contact) (success bool, err error) { var dist int var exists bool var tripletP *list.Element //find distance dist = k.ContactInfo.NodeID.Distance(triplet.NodeID) if -1 == dist { dbg.Printf("Update dist == -1 return\n", Verbose) return true, nil } //search kbucket and return pointer to the Triplet exists, tripletP = k.Buckets[dist].Search(triplet.NodeID) if exists { //move to the tail k.Buckets[dist].MoveToTail(tripletP) success = true } else { if !k.Buckets[dist].IsFull() { //just added to the tail k.Buckets[dist].AddToTail(&triplet) success = true } else { //log.Printf("A bucket is full! Checking...\n") //ping the contant at the head ///get head lFront := k.Buckets[dist].l.Front() var remoteContact *Contact = lFront.Value.(*Contact) ///make ping //log.Printf("Pinging the guy in the front of the list...\n") succ := MakePingCall(k, remoteContact.Host, remoteContact.Port) if !succ { //log.Printf("He failed! Replacing\n") //drop old k.Buckets[dist].Drop(lFront) //add new to tail k.Buckets[dist].AddToTail(&triplet) success = true } else { //log.Printf("He replied! Just ignore the new one\n") //ignore new //move the old one to the tail k.Buckets[dist].MoveToTail(lFront) success = true } } } if k.FirstKBucketStore && success { k.DoJoinFlag = true k.FirstKBucketStore = false } //REVIEW //Should we return any error from this function? return success, nil }
//more arguments for a later time //remoteAddr net.IP, remotePort uint16, doPing bool func DoJoin(dm *DryMartini) bool { var success bool var secToWait time.Duration = 1 dbg.Printf("drymartini.DoJoin()\n", Verbose) success = kademlia.DoJoin(dm.KademliaInst) if !success { return false } dm.DoJoinFlag = false dbg.Printf("doJoin in %d sec\n", Verbose, secToWait) time.Sleep(secToWait) //Store our contact information //TODO StoreContactInfo(dm) return true }
func StoreHandler(k *Kademlia) (chan *PutRequest, chan *GetRequest, chan ID) { var puts chan *PutRequest var gets chan *GetRequest var deletes chan ID puts = make(chan *PutRequest) gets = make(chan *GetRequest) deletes = make(chan ID) go func() { for { var p *PutRequest var g *GetRequest var id ID select { case p = <-puts: //put if k.ValueStore.HashMap[p.key].expireTimer != nil { k.ValueStore.HashMap[p.key].expireTimer.Stop() } dbg.Printf("In put handler for store. key->%s value->%s expires->%v\n", Verbose, p.key.AsString(), p.value, p.duration) k.ValueStore.HashMap[p.key] = StoreItem{p.value, time.AfterFunc(p.duration, func() { k.ValueStore.DeleteChannel <- p.key }), time.Now()} case g = <-gets: //get var si StoreItem var found bool dbg.Printf("In get handler for Store. key->%s", Verbose, g.key.AsString()) si, found = k.ValueStore.HashMap[g.key] g.ReturnChan <- &GetResponse{si.Value, found} case id = <-deletes: delete(k.ValueStore.HashMap, id) } //log.Println("StoreHandler loop end\n") } }() return puts, gets, deletes }
//check our list of existing paths, to see if there are any that haven't expired. Otherwise generate a new one func FindOrGenPath(mDM *DryMartini, minLength int, maxLength int) (bool, int) { var success bool var flowIndex int success, flowIndex = FindGoodPath(mDM) if !success { success, flowIndex = BarCrawl(mDM, "buildingCircuitForProxy", minLength, maxLength) if !success { dbg.Printf("there was an error building the circuit!\n", ERRORS) } } return success, flowIndex }
//encrypts data with pathKeys //pathKeys are in order of closest Nodes key to furthest func WrapOlivesForPath(dm *DryMartini, flowID UUID, pathKeyFlows []FlowIDSymmKeyPair, Data []byte) []byte { var err error pathLength := len(pathKeyFlows) //if only 1 MartiniContact exists in path, then we only construct 1 Olive.. //but that should probably never happen, (assuming always more than 1 hop atm) var innerOlive Olive //might wanna delete this at some point, should be unneccessary. inner olive doesn't need flow id innerOlive.FlowID = flowID innerOlive.Data = Data //dbg.Printf("We are packaging data: %s", string(Data)) var theData []byte theData, err = json.Marshal(innerOlive) if err != nil { dbg.Printf("error marshalling inner Olive:%+v\n", ERRORS, innerOlive) panic(1) } var tempOlive Olive for i := pathLength - 1; i > 0; i-- { //important that flowID is shifted by 1 tempOlive.FlowID = pathKeyFlows[i].FlowID //encrypt the Data (using furthest nodes key) and put it into tempOlive tempOlive.Data = EncryptDataSymm(theData, pathKeyFlows[i].SymmKey) dbg.Printf("USING SYMMKEY and FLOWID: %+v\n", Verbose, pathKeyFlows[i]) //marshal the temp Olive theData, err = json.Marshal(tempOlive) if err != nil { dbg.Printf("error marshalling Olive:%+v, err:%s\n", ERRORS, tempOlive, err) panic(1) } } //dbg.Printf("USING SymmKEY and FlowID: %v\n", pathKeyFlows[0]) theData = EncryptDataSymm(theData, pathKeyFlows[0].SymmKey) return theData }
//makes a DryMartini.ServeDrink call on address with the Olive data, returning success and returned data if any func MakeSendCall(dataLump Olive, nextNodeAddrStr string) (bool, []byte) { var client *rpc.Client var err error dbg.Printf("MakeSendCall:: next: %s!", Verbose, nextNodeAddrStr) if kademlia.RunningTests == true { //log.Printf("Unimplemented\n") //panic(1) var nextNodePort string = strings.Split(nextNodeAddrStr, ":")[1] if nextNodePort == "" { log.Printf("error getting next port: MakeSendCall\n") panic(1) } var portstr string = kademlia.RpcPath + nextNodePort log.Printf("test MakeSendCall to rpcPath:%s\n", portstr) client, err = rpc.DialHTTPPath("tcp", nextNodeAddrStr, portstr) } else { client, err = rpc.DialHTTP("tcp", nextNodeAddrStr) } if err != nil { log.Printf("Error: MakeSendCall, DialHTTP, %s\n", err) return false, nil } //make rpc var res *ServerResp = new(ServerResp) var req *ServerData = new(ServerData) req.Sent = dataLump err = client.Call("DryMartini.ServeDrink", req, res) if err != nil { log.Printf("Error: SendCall, Call, %s\n", err) return false, nil } dbg.Printf("got SendCall response: %s:%v\n", Verbose, nextNodeAddrStr, res.Success) client.Close() return res.Success, res.Data }
func (k *Kademlia) FindNode(req FindNodeRequest, res *FindNodeResult) error { var err error //Update(k, req.Sender) k.UpdateChannel <- req.Sender dbg.Printf("RPC: FindNode from %s ---> %s\n", Verbose, req.Sender.NodeID.AsString(), k.ContactInfo.AsString()) res.Nodes, err = FindKClosest(k, req.NodeID, req.Sender.NodeID) res.MsgID = CopyID(req.NodeID) ///REVIEW: What kind of error can happen in this function? return err }
//send Data using the path info stored at FlowIndex func SendData(dm *DryMartini, flowIndex int, data string) (response string, success bool) { var flowInfo FlowInfo var flowID UUID var found bool //map index to flowID flowInfo, found = dm.MapFlowIndexToFlowID[flowIndex] if !found { dbg.Printf("No map from flowIndex to flowID\n", ERRORS) return "", false } else { flowID = flowInfo.FlowID dbg.Printf("Found map from flowIndex to flowID\n", Verbose) } //wrap data var sendingOlive Olive sendingOlive.Data = WrapOlivesForPath(dm, flowID, dm.Momento[flowID], []byte(data)) //first olive gets flowID for first node in path sendingOlive.FlowID = dm.Momento[flowID][0].FlowID var nextNodeAddrStr string = dm.Bartender[flowID].NextNodeIP + ":" + strconv.FormatUint(uint64(dm.Bartender[flowID].NextNodePort), 10) //make send rpc var encResponseData []byte var responseData []byte success, encResponseData = MakeSendCall(sendingOlive, nextNodeAddrStr) if !success { dbg.Printf("Some terrible error happened while sending\n", ERRORS) return "", false } //unwrap data responseData = UnwrapOlivesForPath(dm, dm.Momento[flowID], encResponseData) log.Printf("SEND REPLY: %s\n", string(responseData)) return string(responseData), true }
func DoHTTPRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { var success bool var flowIndex int var response string success, flowIndex = drymartini.FindOrGenPath(myDryMartini, DefaultCircLength, DefaultCircLength) if !success { return r, goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusInternalServerError, "error building circuit") } response, success = drymartini.SendData(myDryMartini, flowIndex, r.URL.String()) if !success { log.Printf("there was an error sending the request:%s\n", r.URL.String()) return r, goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusInternalServerError, "error sending request") } var contentType string = http.DetectContentType([]byte(response)) dbg.Printf("detected response as having content-type:%s\n", pVerb, contentType) dbg.Printf("request url was:%s\n", pVerb, r.URL.String()) //gotta set the content-type manually, detectContentType doesn't seem to work for .css //kept setting it as "text/plain". there's probably a much nice way than this, whatevs. fake it til you make it if strings.Contains(r.URL.String(), ".css") { contentType = "text/css" } return r, goproxy.NewResponse(r, contentType, http.StatusOK, response) }
func MakeStore(k *Kademlia, remoteContact *Contact, Key ID, Value []byte) bool { var client *rpc.Client var localContact *Contact var storeReq *StoreRequest var storeRes *StoreResult var remoteAddrStr string var remotePortStr string var err error localContact = &(k.ContactInfo) remoteAddrStr = remoteContact.Host.String() + ":" + strconv.Itoa(int(remoteContact.Port)) dbg.Printf("MakeStore: From %s --> To %s\n", Verbose, localContact.AsString(), remoteContact.AsString()) storeReq = new(StoreRequest) storeReq.MsgID = NewRandomID() storeReq.Sender = CopyContact(localContact) storeReq.Key = CopyID(Key) storeReq.Value = Value storeRes = new(StoreResult) remotePortStr = strconv.Itoa(int(remoteContact.Port)) //Dial the server if RunningTests == true { //if we're running tests, need to DialHTTPPath var portstr string = RpcPath + remotePortStr client, err = rpc.DialHTTPPath("tcp", remoteAddrStr, portstr) } else { client, err = rpc.DialHTTP("tcp", remoteAddrStr) } if err != nil { Printf("Error: MakeStore, DialHTTP, %s\n", k, Verbose, err) return false } //make the rpc err = client.Call("Kademlia.Store", storeReq, &storeRes) if err != nil { Printf("Error: MakeStore, Call, %s\n", k, Verbose, err) return false } client.Close() //update the remote node contact information k.UpdateChannel <- *remoteContact return true }
func pathEndAction(payload string) ([]byte, error) { var err error var responseBody []byte var resp *http.Response resp, err = http.Get(payload) if err != nil { log.Printf("error for http.get: %s\n", err) return responseBody, err } //log.Printf("pathEndAction response:%+v\n", resp) responseBody, err = ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { dbg.Printf("error reading response.Body: %s\n", true, err) } return responseBody, err }
//calls the RPC function 'CreateCircuit' on the next DryMartini in the route func MakeCircuitCreateCall(dm *DryMartini, nextNodeAddrStr string, encryptedArray [][]byte) bool { var client *rpc.Client var err error dbg.Printf("MakeCircuitCreateCall: %s\n", Verbose, nextNodeAddrStr) if kademlia.RunningTests == true { //log.Printf("Unimplemented\n") //panic(1) var nextNodePort string = strings.Split(nextNodeAddrStr, ":")[1] if nextNodePort == "" { dbg.Printf("error getting next port: MakeSendCall\n", ERRORS) return false } var portstr string = kademlia.RpcPath + nextNodePort dbg.Printf("test makeCircuitCreateCall to rpcPath:%s\n", Verbose, portstr) client, err = rpc.DialHTTPPath("tcp", nextNodeAddrStr, portstr) } else { client, err = rpc.DialHTTP("tcp", nextNodeAddrStr) } if err != nil { dbg.Printf("Error: MakeCircuitCreateCall, DialHTTP, %s\n", ERRORS, err) return false } //make rpc var req *CCRequest = new(CCRequest) req.EncryptedData = encryptedArray var res *CCResponse = new(CCResponse) err = client.Call("DryMartini.CreateCircuit", req, res) if err != nil { dbg.Printf("Error: CreateCircuit, Call, %s\n", ERRORS, err) return false } dbg.Printf("got DistributeSymm response: %s:%v\n", Verbose, nextNodeAddrStr, res.Success) client.Close() return res.Success }
//rpc function. Called when creating a Circuit. Initializes FlowID and structure at this DM (so we know what SymmKey to use when forwarding traffic later) func (dm *DryMartini) CreateCircuit(req CCRequest, res *CCResponse) error { var nextNodeOlive *Olive = new(Olive) var sha_gen hash.Hash = sha1.New() var decryptedData []byte var err error var encryptedData [][]byte dbg.Printf("CreateCircuit, my pubKey:%s\n", Verbose, dm.myMartiniContact.PubKey) decryptedData, err = rsa.DecryptOAEP(sha_gen, nil, dm.KeyPair, req.EncryptedData[0], nil) if err != nil { dbg.Printf("Error: DryMartini.CreateCircuit.Decrypt( %s). IP:%s Port:%d\n", ERRORS, err, dm.myMartiniContact.NodeIP, dm.myMartiniContact.NodePort) res.Success = false return nil //Change to valid error } err = json.Unmarshal(decryptedData, nextNodeOlive) if err != nil { dbg.Printf("Error: DryMartini.CreateCircuit.Unmarshal( %s)\n", ERRORS, err) res.Success = false return nil //Change to valid error } dm.Bartender[nextNodeOlive.FlowID] = nextNodeOlive.Route dbg.Printf("NextNodeOlive_data:%s\n", Verbose, string(nextNodeOlive.Data)) if len(req.EncryptedData) != 1 { dbg.Printf("CreateCircuit: len(%d) \n", Verbose, len(req.EncryptedData)) encryptedData = req.EncryptedData[1:] var nextNodeAddrStr string = nextNodeOlive.Route.NextNodeIP + ":" + strconv.FormatUint(uint64(nextNodeOlive.Route.NextNodePort), 10) dbg.Printf("NextHopIs: %s\n", Verbose, nextNodeAddrStr) res.Success = MakeCircuitCreateCall(dm, nextNodeAddrStr, encryptedData) } else { res.Success = true } return nil }
// SEND IT RECURSIVELY, THATS HOW BARS WORK //rpc function. Called with wrapped Olive. Unwrap and call MakeSendCall on next address if necessary. func (dm *DryMartini) ServeDrink(req ServerData, resp *ServerResp) error { var raw_data []byte var decolive Olive var currFlow UUID var responseData []byte var err error var symmKey UUID currFlow = req.Sent.FlowID symmKey = dm.Bartender[currFlow].SymmKey raw_data = DecryptDataSymm(req.Sent.Data, dm.Bartender[currFlow].SymmKey) if Verbose { log.Printf("Getting a ServeDrink call!\n") log.Printf("We were given olive: %+v\n", req.Sent) log.Printf("Will use SymmKey: %v\n", symmKey) log.Printf("RAW DATA: %v\n", raw_data) log.Printf("RAW DATA(s): %s\n", string(raw_data)) } // Unmarshal the new olive err = json.Unmarshal(raw_data, &decolive) if err != nil { log.Printf("Unmarshal error: %s\n", err) resp.Success = false return nil } //this is the last node in the flow path if dm.Bartender[currFlow].NextNodeIP == "end" { dbg.Printf("We made it to the end!\n", Verbose) var payload string = string(decolive.Data) var marshalledOlive []byte var responsePayload []byte dbg.Printf("PAYLOAD: %s\n", Verbose, payload) responsePayload, err = pathEndAction(payload) if err != nil { responsePayload = []byte(fmt.Sprintf("error completing endPathAction with payload:%s", payload)) } var responseOlive Olive //flowid already set. Don't mess //responseOlive.FlowID = currFlow //log.Printf("path end action completed: setting response:%s\n", string(responsePayload)) responseOlive.Data = responsePayload marshalledOlive, err = json.Marshal(responseOlive) if err != nil { log.Printf("error marhsalling responseOlive: %s\n", err) resp.Success = false return nil } encData := EncryptDataSymm(marshalledOlive, symmKey) resp.Data = encData resp.Success = true return nil } //this is not the last node in the chain //Send the new olive! //TODO: End case should maybe return false? It should check for failure. var nextNodeAddrStr string = dm.Bartender[currFlow].NextNodeIP + ":" + strconv.FormatUint(uint64(dm.Bartender[currFlow].NextNodePort), 10) resp.Success, responseData = MakeSendCall(decolive, nextNodeAddrStr) if !resp.Success { log.Printf("Error: ServeDrink, MakeSendCall failed\n") return nil } var marshalledOlive []byte var responseOlive Olive //flowID already set. don't mess //responseOlive.FlowID = currFlow responseOlive.Data = responseData marshalledOlive, err = json.Marshal(responseOlive) if err != nil { log.Printf("error marhsalling responseOlive: %s\n", err) resp.Success = false return nil } encData := EncryptDataSymm(marshalledOlive, symmKey) resp.Data = encData resp.Success = true return nil }
//returns array of random known-to-be-live MartiniContacts (for use as a path) func GeneratePath(dm *DryMartini, min, max int) (mcPath []MartiniContact) { const safetyMax int = 50 var err error //var threshold int //var myRand *big.Int var randId kademlia.ID var pathMap map[MartiniContact]bool = make(map[MartiniContact]bool) //minBig := big.NewInt(int64(min)) //myRand, err = rand.Int(rand.Reader, big.NewInt(int64(max-min))) //threshold = int((minBig.Int64() + myRand.Int64())) mcPath = make([]MartiniContact, max) var safetyCounter int = 0 for i := 0; i < max; i++ { var foundNodes []kademlia.FoundNode var success bool safetyCounter++ dbg.Printf("Attempt %d to add to path (curlength %d)\n", Verbose, safetyCounter, i) if safetyCounter == safetyMax { dbg.Printf("GeneratePath failure. Made %d attempts. unable to get enough MartiniContacts to build path of length:%d\n", ERRORS, safetyMax, max) panic(1) } randId = kademlia.NewRandomID() success, foundNodes, _, err = kademlia.IterativeFind(dm.KademliaInst, randId, 1) if len(foundNodes) == 0 { dbg.Printf("GeneratePath:316. no nodes found; continueing\n", Verbose) i-- continue } /* dbg.Printf("GeneratePath: found live nodes:\n") kademlia.PrintArrayOfFoundNodes(&foundNodes) */ if err != nil { dbg.Printf("error finding random NodeID:%s, success:%s msg:%s\n", ERRORS, randId, success, err) panic(1) } fuckthis, fuckingo := rand.Int(rand.Reader, big.NewInt(int64(len(foundNodes)))) if fuckingo != nil { dbg.Printf("error making rand:%s\n", ERRORS, fuckingo) } index := int(fuckthis.Int64()) var hashedID kademlia.ID = foundNodes[index].NodeID.SHA1Hash() dbg.Printf("generatePath: findMartiniContact for mc:%+v\n", Verbose, foundNodes[index]) var tempMC MartiniContact tempMC, success = findMartiniContact(dm, hashedID) if !success { dbg.Printf("error finding MartiniContact with key:%s. err:%s\n", ERRORS, hashedID.AsString(), err) i-- continue } _, alreadyInPath := pathMap[tempMC] if alreadyInPath { dbg.Printf("trying to make a circular path. skipping!\n", Verbose) i-- continue } else { pathMap[tempMC] = true mcPath[i] = tempMC } //err = json.Unmarshal(mcBytes, &mcPath[i]) dbg.Printf("GeneratePath path-mid-build: %+v\n", Verbose, mcPath) } return }
//generate and prep a path for traffic through the DryMartini network. Store FlowInfo in //DryMartini.MapFlowIndexToFlowID and return index. rdy for SendData func BarCrawl(m *DryMartini, request string, min int, max int) (bool, int) { var success bool //Generate a path var chosenPath []MartiniContact chosenPath = GeneratePath(m, min, max) // Send the recursie request var encryptedSym [][]byte = make([][]byte, len(chosenPath)) var jar []*Olive = make([]*Olive, len(chosenPath)) var myFlowID UUID = NewUUID() //log.Printf("chosenPath: %+v\n", chosenPath) var i int var tempFlowID UUID // Build an array of Olives for i = 0; i < (len(chosenPath) - 1); i++ { jar[i] = new(Olive) //make a new UUID for each node in the circuit tempFlowID = NewUUID() jar[i].FlowID = tempFlowID jar[i].Data = []byte("testData_" + strconv.Itoa(i)) // Built its martiniPick jar[i].Route.NextNodeIP = chosenPath[i+1].NodeIP jar[i].Route.NextNodePort = chosenPath[i+1].NodePort jar[i].Route.SymmKey = NewUUID() // First one? if i == 0 { jar[i].Route.PrevNodeIP = m.myMartiniContact.NodeIP jar[i].Route.PrevNodePort = m.myMartiniContact.NodePort } else { jar[i].Route.PrevNodeIP = chosenPath[i-1].NodeIP jar[i].Route.PrevNodePort = chosenPath[i-1].NodePort } //append the new SymmKeyFlowID pair to momento. so we can use this to build wrapped olive with correct flowID m.Momento[myFlowID] = append(m.Momento[myFlowID], FlowIDSymmKeyPair{SymmKey: jar[i].Route.SymmKey, FlowID: tempFlowID}) } // Do the last one jar[i] = new(Olive) tempFlowID = NewUUID() jar[i].FlowID = tempFlowID jar[i].Route.NextNodeIP = "end" jar[i].Route.PrevNodeIP = chosenPath[i-1].NodeIP jar[i].Route.PrevNodePort = chosenPath[i-1].NodePort jar[i].Route.SymmKey = NewUUID() jar[i].Data = []byte(request) m.Momento[myFlowID] = append(m.Momento[myFlowID], FlowIDSymmKeyPair{SymmKey: jar[i].Route.SymmKey, FlowID: tempFlowID}) var tempBytes []byte var err error var sha_gen hash.Hash //log.Printf("building jar, flowID:%s\n", flowID.AsString()) // Encrypt everything. for i = 0; i < len(chosenPath); i++ { dbg.Printf("jar[%d]: %+v\n", Verbose, i, jar[i]) tempBytes, err = json.Marshal(jar[i]) if err != nil { dbg.Printf("Error Marhsalling Olive: %+v\n", ERRORS, jar[i]) return false, -1 } sha_gen = sha1.New() dbg.Printf("encrypting CC element:%s with pubkey:%s\n", Verbose, i, chosenPath[i].PubKey) encryptedSym[i], err = rsa.EncryptOAEP(sha_gen, rand.Reader, &(chosenPath[i].GetReadyContact().PubKey), tempBytes, nil) if err != nil { dbg.Printf("BarCrawl.EncryptOAEP %s. Payload size:%d\n", ERRORS, err, len(tempBytes)) return false, -1 } dbg.Printf("path, %d %s:%d\n", Verbose, i, chosenPath[i].NodeIP, chosenPath[i].NodePort) } //Wrap and send an Olive var nextNodeAddrStr string = chosenPath[0].NodeIP + ":" + strconv.FormatUint(uint64(chosenPath[0].NodePort), 10) success = MakeCircuitCreateCall(m, nextNodeAddrStr, encryptedSym) //Thing to remember locally, so we know where to send var ourFirstPick MartiniPick if success { m.MapFlowIndexToFlowID[m.EasyNewFlowIndex] = FlowInfo{myFlowID, time.Now().Add(time.Duration(FlowExpireTime) * time.Millisecond)} m.EasyNewFlowIndex++ // Build a pick for the first hop ourFirstPick.NextNodeIP = chosenPath[0].NodeIP ourFirstPick.NextNodePort = chosenPath[0].NodePort m.Bartender[myFlowID] = ourFirstPick } return success, (m.EasyNewFlowIndex - 1) }
//findType (1: findNode. 2: findValue) func IterativeFind(k *Kademlia, searchID ID, findType int) (bool, []FoundNode, []byte, error) { var value []byte var shortList *list.List //shortlist is the list we are going to return var closestNode ID var localContact *Contact = &(k.ContactInfo) var sentMap map[ID]bool //map of nodes we've sent rpcs to var liveMap map[ID]bool //map of nodes we've gotten responses from var kClosestArray []FoundNode var err error dbg.Printf("IterativeFind: searchID=%s findType:%d\n", Verbose, searchID.AsString(), findType) shortList = list.New() //list of kConst nodes we're considering sentMap = make(map[ID]bool) liveMap = make(map[ID]bool) kClosestArray, err = FindKClosest(k, searchID, localContact.NodeID) Assert(err == nil, "Kill yourself and fix me") Assert(len(kClosestArray) > 0, "I don't know anyone!") //adds len(KClosestArray) nodes to the shortList in order for i := 0; (i < KConst) && (i < len(kClosestArray)); i++ { var newNode *FoundNode var newNodeDist int newNode = &kClosestArray[i] newNodeDist = newNode.NodeID.Distance(searchID) var e *list.Element = shortList.Front() for ; e != nil; e = e.Next() { var dist int dist = e.Value.(*FoundNode).NodeID.Distance(searchID) //if responseNode is closer than node in ShortList, add it if newNodeDist < dist { shortList.InsertBefore(newNode, e) //node inserted! getout break } } if e == nil { //node is farthest yet shortList.PushBack(newNode) } } //set closestNode to first item from shortlist closestNode = shortList.Front().Value.(*FoundNode).NodeID var stillProgress bool = true NodeChan := make(chan *FindStarCallResponse, AConst) for stillProgress { var i int stillProgress = false //log.Printf("in main findNode iterative loop. shortList.Len()=%d len(liveMap)=%d\n", shortList.Len(),len(liveMap)) e := shortList.Front() for i = 0; i < AConst && e != nil; e = e.Next() { foundNodeTriplet := e.Value.(*FoundNode) _, inSentList := sentMap[foundNodeTriplet.NodeID] if inSentList { //don't do RPC on nodes in SentList //don't increment i (essentially the sentNodes counter) continue } //send rpc if findType == 1 { //FindNode //made MakeFindNodeCall take a channel, where it puts the result if RunningTests { Printf("makeFindNodeCall to ID=%s\n", k, Verbose, foundNodeTriplet.NodeID.AsString()) } go MakeFindNodeCall(k, foundNodeTriplet.FoundNodeToContact(), searchID, NodeChan) } else if findType == 2 { //FindValue if RunningTests { Printf("makeFindValueCall to ID=%s\n", k, Verbose, foundNodeTriplet.NodeID.AsString()) } go MakeFindValueCall(k, foundNodeTriplet.FoundNodeToContact(), searchID, NodeChan) } else { Assert(false, "Unknown case") } //put to sendList sentMap[foundNodeTriplet.NodeID] = true //e = e.Next() i++ //log.Printf("iterativeFindNode Find* rpc loop end\n") } //log.Printf("iterativeFind: Made FindNodeCall on %d hosts\n", i) var numProbs = i //wait for reply for i = 0; i < numProbs; i++ { //log.Printf("IterativeFind: α loop start\n") var foundStarResult *FindStarCallResponse foundStarResult = <-NodeChan if RunningTests { Printf("IterativeFind: Reading response from: %s\n", k, Verbose, foundStarResult.Responder.NodeID.AsString()) } //TODO: CRASHES IF ALL ALPHA RETURN EMPTY if foundStarResult.Responded { //Non data trash //Take its data liveMap[foundStarResult.Responder.NodeID] = true if findType == 1 { //FindNode Assert(foundStarResult.ReturnedFNRes != nil, "findStarResult Struct error in iterativeFindNode") addResponseNodesToSL(foundStarResult.ReturnedFNRes.Nodes, shortList, sentMap, searchID) } else { //FindValue Assert(foundStarResult.ReturnedFVRes != nil, "findStarResult Struct error in iterativeFindValue") //log.Printf("got response from %+v findvalue _%s_\n", foundStarResult.ReturnedFVRes, string(foundStarResult.ReturnedFVRes.Value)) if foundStarResult.ReturnedFVRes.Value != nil { var nArray []FoundNode = []FoundNode{*(foundStarResult.Responder)} //TODO //When an iterativeFindValue succeeds, the initiator must store the key/value pair at the closest node seen which did not return the value. return true, nArray, foundStarResult.ReturnedFVRes.Value, nil } else { if RunningTests { Printf("Could not found value in this node", k, Verbose) } } addResponseNodesToSL(foundStarResult.ReturnedFVRes.Nodes, shortList, sentMap, searchID) } distance := searchID.Distance(shortList.Front().Value.(*FoundNode).NodeID) if distance < searchID.Distance(closestNode) { //log.Printf("New closest! dist:%d\n", distance) closestNode = foundStarResult.Responder.NodeID stillProgress = true } else { //closestNode didn't change, flood RPCs and prep to return stillProgress = false } } else { dbg.Printf("iterativeFind: node:%+v failed to respond, removing from shortlist\n", Verbose, foundStarResult.Responder) //It failed, remove it from the shortlist for e := shortList.Front(); e != nil; e = e.Next() { if e.Value.(*FoundNode).NodeID.Equals(foundStarResult.Responder.NodeID) { shortList.Remove(e) break } } } //log.Printf("IterativeFind: α loop end\n") } } shortArray, value := sendRPCsToFoundNodes(k, findType, localContact, searchID, shortList, sentMap, liveMap) if findType == 1 { if Verbose { PrintArrayOfFoundNodes(&shortArray) } return true, shortArray, value, nil } else if findType == 2 && value != nil { return true, shortArray, value, nil } //if we're here and we were looking for a value, we failed. return false and foundnodes. return false, shortArray, value, nil }
//Makes a FindNodeCall on remoteContact. returns list of KClosest nodes on that contact, and the id of the remote node //REVIEW //George: On the ground that this should be an asynchronous call, I modified the definition of the function //func MakeFindNodeCall(localContact *Contact, remoteContact *Contact, NodeChan chan *FindNodeCallResponse) (*FindNodeResult, bool) { func MakeFindNodeCall(k *Kademlia, remoteContact *Contact, searchKey ID, NodeChan chan *FindStarCallResponse) { var fnRequest *FindNodeRequest var fnResult *FindNodeResult var remoteAddrStr string var remotePortStr string var client *rpc.Client var resultSet *FindStarCallResponse var err error var localContact *Contact localContact = &(k.ContactInfo) remoteAddrStr = remoteContact.Host.String() + ":" + strconv.Itoa(int(remoteContact.Port)) dbg.Printf("MakeFindNodeCall: From %s --> To %s\n", Verbose, localContact.AsString(), remoteContact.AsString()) fnRequest = new(FindNodeRequest) fnRequest.MsgID = NewRandomID() fnRequest.Sender = CopyContact(localContact) fnRequest.NodeID = CopyID(searchKey) fnResult = new(FindNodeResult) resultSet = new(FindStarCallResponse) resultSet.ReturnedFNRes = fnResult resultSet.ReturnedFVRes = nil resultSet.Responder = remoteContact.ContactToFoundNode() resultSet.Responded = false remotePortStr = strconv.Itoa(int(remoteContact.Port)) //Dial the server if RunningTests == true { //if we're running tests, need to DialHTTPPath var portstr string = RpcPath + remotePortStr //log.Printf("test FindNodeCall to rpcPath:%s\n", portstr) client, err = rpc.DialHTTPPath("tcp", remoteAddrStr, portstr) } else { client, err = rpc.DialHTTP("tcp", remoteAddrStr) } if err != nil { dbg.Printf("Error: MakeFindNodeCall, DialHTTP, %s\n", Verbose, err) NodeChan <- resultSet return } err = client.Call("Kademlia.FindNode", fnRequest, &fnResult) if err != nil { Printf("Error: MakeFindNodeCall, Call, %s\n", k, Verbose, err) NodeChan <- resultSet return } //if you get any nodes update you kbuckets with them //Jack: REVIEW: I'm not sure if we do want to update on only //'heard of' nodes. Only when we make direct contact no? //Also look at similar block in MakeFindValueCall /* for _, node := range fnResult.Nodes { k.UpdateChannel <- *(node.FoundNodeToContact()) }*/ // Mark the result as being good resultSet.Responded = true NodeChan <- resultSet client.Close() //update the remote node contact information k.UpdateChannel <- *remoteContact return }
//func MakeFindValue(k *Kademlia, remoteContact *Contact, Key ID, fvChan chan *FindValueCallResponse) (bool, []byte, *[]FoundNode) { func MakeFindValueCall(k *Kademlia, remoteContact *Contact, Key ID, fvChan chan *FindStarCallResponse) { var findValueReq *FindValueRequest var findValueRes *FindValueResult var remoteAddrStr string var remotePortStr string var client *rpc.Client var localContact *Contact var resultSet *FindStarCallResponse var err error localContact = &(k.ContactInfo) remoteAddrStr = remoteContact.Host.String() + ":" + strconv.Itoa(int(remoteContact.Port)) dbg.Printf("MakeFindValue[%s]: From %s --> To %s\n", Verbose, Key.AsString(), localContact.AsString(), remoteContact.AsString()) findValueReq = new(FindValueRequest) findValueReq.MsgID = NewRandomID() findValueReq.Sender = CopyContact(localContact) findValueReq.Key = CopyID(Key) findValueRes = new(FindValueResult) resultSet = new(FindStarCallResponse) resultSet.ReturnedFVRes = findValueRes resultSet.ReturnedFNRes = nil resultSet.Responder = remoteContact.ContactToFoundNode() resultSet.Responded = false remotePortStr = strconv.Itoa(int(remoteContact.Port)) //Dial the server if RunningTests == true { //if we're running tests, need to DialHTTPPath var portstr string = RpcPath + remotePortStr //log.Printf("test FindNodeValue to rpcPath:%s\n", portstr) client, err = rpc.DialHTTPPath("tcp", remoteAddrStr, portstr) } else { client, err = rpc.DialHTTP("tcp", remoteAddrStr) } if err != nil { dbg.Printf("Error: MakeFindValueCall, DialHTTP, %s\n", Verbose, err) fvChan <- resultSet return } //make rpc err = client.Call("Kademlia.FindValue", findValueReq, &findValueRes) if err != nil { Printf("Error: MakeFindValue, Call, %s\n", k, Verbose, err) fvChan <- resultSet return } //Mark the result as being good resultSet.Responded = true fvChan <- resultSet client.Close() //update the remote node contact information k.UpdateChannel <- *remoteContact return }