void TcpScanner::init() { src_port = getFirstPID(); port_count = 0; resolve_service_names = 1; /* craft template packet */ template_packet.ip.ihl = 5; template_packet.ip.version = 4; template_packet.ip.tos = 0; template_packet.ip.tot_len = htons(sizeof(template_packet)); template_packet.ip.frag_off = 0; template_packet.ip.ttl = getTTL(); // TODO need to update template after change TTL template_packet.ip.protocol = IPPROTO_TCP; template_packet.ip.check = 0; template_packet.tcp.ack_seq = 0; template_packet.tcp.res1 = 0; template_packet.tcp.doff = 5; template_packet.tcp.fin = 0; // All TCP flags off by default template_packet.tcp.syn = 0; template_packet.tcp.rst = 0; template_packet.tcp.psh = 0; template_packet.tcp.ack = 0; template_packet.tcp.urg = 0; template_packet.tcp.res2 = 0; // template_packet.tcp.ece = 0; // template_packet.tcp.cwr = 0; template_packet.tcp.window = htons(512); template_packet.tcp.check = 0; template_packet.tcp.urg_ptr = 0; syn_flag = 0; rst_flag = 0; fin_flag = 0; psh_flag = 0; ack_flag = 0; urg_flag = 0; ece_flag = 0; cwr_flag = 0; }
// TODO // - Return 0 ONLY when there is no packet to send (not on the last packet) // - Make a hardcoded template packet to prevent having to craft it each time int TcpScanner::sendPacket() { if (debug > 3) printf("TcpScanner::sendPacket: Called\n"); // dumpPortList(); // TODO findNextScannablePort(); // Updates pcurrent_host_element // First check if there's anything left to scan. Return 0 if not. // // This involves moving onto the next host/port and checking if we've found // something that can be scanned. It's a bit untidy, but it's important that // this func can be called even if nothing needs scanning. #ifdef DEBUG if (!pcurrent_host_element) { printf("DEBUG WARNING: TcpScanner::sendPacket called with pcurrent_host_element = null\n"); } #endif // If all host elements have been deleted, we're done. if (!pcurrent_host_element) return 0; #ifdef DEBUG if (!pcurrent_host_element->pcurrent_port) { printf("DEBUG WARNING: TcpScanner::sendPacket called with pcurrent_host_element->pcurrent_port = null\n"); } #endif // Note the current port element // We need to note this so we can tell we've been completely round the port list struct port_element *pstart_port_element = pcurrent_host_element->pcurrent_port; // Increment the port pointer on this host pcurrent_host_element->pcurrent_port = pcurrent_host_element->pcurrent_port->pnext; int more_ports = 0; // Move onto next host pcurrent_host_element = pcurrent_host_element->pnext; // optimisation to avoid too much pointer defrerencing. Hardly worth it. struct port_element *pcurhost_curport = pcurrent_host_element->pcurrent_port; while (!more_ports and pcurhost_curport != pstart_port_element) { // can we send to the current port in this portlist? if (pcurhost_curport->send_count < tries) { // we can send to this more_ports = 1; } else { // we can't send. increment the port pointer on this host pcurrent_host_element->pcurrent_port = pcurhost_curport->pnext; // change to next host pcurrent_host_element = pcurrent_host_element->pnext; pcurhost_curport = pcurrent_host_element->pcurrent_port; } } // Return 0 if there is nothing left to scan if (!(more_ports or pcurhost_curport->send_count < tries)) { return 0; } /* vars for sending */ struct sockaddr_in sin; int send_socket; // Make a new packet based on the template packet struct send_tcp packet; memcpy(&packet, &template_packet, sizeof(packet)); // Fill in dynamic fields in new packet memcpy(&packet.ip.saddr, &src_ip, sizeof(src_ip)); packet.tcp.source = htons(getNextSourcePort()); packet.ip.daddr = pcurrent_host_element->ip.s_addr; packet.tcp.dest = htons(pcurrent_host_element->pcurrent_port->port); packet.tcp.seq = htonl(syncookie(packet.ip.saddr, packet.ip.daddr, packet.tcp.source, packet.tcp.dest)); packet.tcp.fin = fin_flag; packet.tcp.syn = syn_flag; packet.tcp.rst = rst_flag; packet.tcp.psh = psh_flag; packet.tcp.ack = ack_flag; packet.tcp.urg = urg_flag; packet.tcp.res2 = ece_flag; // packet.tcp.ece = ece_flag; // packet.tcp.cwr = cwr_flag; packet.ip.ttl = getTTL(); // Now open the raw socket for sending sin.sin_family = AF_INET; sin.sin_port = packet.tcp.source; sin.sin_addr.s_addr = packet.ip.daddr; send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); int options; options = O_NONBLOCK | fcntl(send_socket, F_GETFL); if(fcntl(send_socket, F_SETFL, options) < 0) { perror("FCNTL"); exit(1); } int one = 1; int *oneptr = &one; // TODO Note what these socket options actually do if (setsockopt(send_socket, IPPROTO_IP, IP_HDRINCL, oneptr, sizeof(one)) == -1) { printf("setsockopt: set IP_HDRINCL failed\n"); } if (setsockopt(send_socket, SOL_SOCKET, SO_BROADCAST, oneptr, sizeof(one)) == -1) { printf("libnet_open_raw_sock: set SO_BROADCAST failed\n"); } // From synhose.c by knight pseudo_hdr_tcp.source_address = packet.ip.saddr; pseudo_hdr_tcp.dest_address = packet.ip.daddr; pseudo_hdr_tcp.placeholder = 0; pseudo_hdr_tcp.protocol = IPPROTO_TCP; pseudo_hdr_tcp.tcp_length = htons(sizeof(packet.tcp)); // recalc checksum packet.ip.check = 0; packet.tcp.check = 0; packet.ip.check = in_cksum((unsigned short *)&packet.ip, sizeof(packet.ip)); memcpy((char *)&pseudo_hdr_tcp.tcp, (char *)&packet.tcp, sizeof(pseudo_hdr_tcp.tcp)); packet.tcp.check = in_cksum((unsigned short *)&pseudo_hdr_tcp, sizeof(pseudo_hdr_tcp)); // send packet if (verbose > 1) printf("Sending packet to %s:%d\n", inet_ntoa(pcurrent_host_element->ip), pcurrent_host_element->pcurrent_port->port); sendto(send_socket, &packet, sizeof(packet), 0, (struct sockaddr *)&sin, sizeof(sin)); close(send_socket); // Increment number of times this port has been scanned pcurrent_host_element->pcurrent_port->send_count++; // Delete from list if unless we're going to scan it again // TODO This is elegant, but REALLY hurts performance. //if (pcurrent_host_element->pcurrent_port->send_count >= tries) { // deletePort(pcurrent_host_element, pcurrent_host_element->pcurrent_port); //} // Return the length of the packet we sent return sizeof(packet); }
/******************************************************************* * Function Name: externalFunction * Description: the Network gets input from outside ********************************************************************/ Model <SNetwork::externalFunction( const ExternalMessage &msg ){ if (msg.port() == peer_online) { thegraph->online(msg.value()); //adds a node to the graph with the given value if(VERBOSE) cout<<"node "<<msg.value()<<" inserted\n"; //holdIn( active, Time(0.00f)); } else if (msg.port() == peer_offline){ int inpeer = msg.value(); //get all the connected nodes a disconnect them, plus let them know they've been disconnected set<int> connected = thegraph->getConnectedNodes(inpeer); set<int>::iterator sit; for ( sit=connected.begin() ; sit != connected.end(); sit++ ){ thegraph->disconnect(inpeer, *sit); //disconnect them DisconnectionQueue.push(buildMessage(*sit, inpeer)); //enqueue a message saying peer "inpeer" disconnects from "*sit" } thegraph->offline(inpeer); if(VERBOSE) cout<<"node "<<msg.value()<<" removed\n"; //holdIn( active, Time(0.00f)); } else if (msg.port() == peer_connect){ int twonumbers, from, to; twonumbers = msg.value(); from = getPeerId(twonumbers); //first and second field encoding of the peers to = getMessageId(twonumbers); if(VERBOSE) cout<<"connecting "<<from<<" to "<< to<<"\n"; if(thegraph->connect(from,to)) ConnectionQueue.push(buildMessage(to, from, 1)); // enqueue a connection message : adding the TTL makes it different from a disconnect message, further down the road //holdIn( active, Time(0.00f)); } else if (msg.port() == peer_disconnect){ int twonumbers, from, to; twonumbers = msg.value(); from = getPeerId(twonumbers); //first and second field encoding of the peers to = getMessageId(twonumbers); if(VERBOSE) cout<<"disconnecting "<<from<<" and "<< to<<"\n"; if(thegraph->disconnect(from, to)) DisconnectionQueue.push(twonumbers); // enqueue the original message to be re-output as confirmation that connection took place //holdIn( active, Time(0.00f)); } else if (msg.port() == inroute){ //routing=true; int inpeer, TTL, messageId; inpeer = getPeerId(msg.value()); TTL= getTTL(msg.value()); messageId = getMessageId(msg.value()); if(VERBOSE) cout<<"about to route a message from"<<inpeer<<"\n"; //get all the connected nodes and enqueue the "arrival of the message" event for all these new nodes //find the nodes connected to this one set<int> connected = thegraph->getConnectedNodes(inpeer); //if(VERBOSE) cout<<"loop for enqueuing nodes :"<<connected.size()<<" nodes to enqueue"; set<int>::iterator sit; //if(VERBOSE) cout << "connected nodes contains:"; for ( sit=connected.begin() ; sit != connected.end(); sit++ ){ // if(VERBOSE) cout<<"bang! "<<*sit<<"\n"; EvQ.push(makeNetworkEvent(messageId, *sit, TTL, 0.0f)); //enqueue a network event with the "*sit" peer (the other parts are not used for now) //holdIn( active, Time(0.01f)); } } // TEST : no external transition unless we're passive if (this->state()==passive){ holdIn( active, Time(0,0,0,120)); //wait 120ms before doing something } return *this ; }
/******************************************************************* * Function Name: externalFunction * Description: the Network gets input from outside ********************************************************************/ Model <SNetwork::externalFunction( const ExternalMessage &msg ){ //advance my internal time if(VERBOSE) cout<<"External Transition :"<<endl<<"time: "<<msg.time().asMsecs()<<endl; currenttimefloat = msg.time().asMsecs(); if (msg.port() == peer_online) { thegraph->online(msg.value()); //adds a node to the graph with the given value if(VERBOSE) cout<<"node "<<msg.value()<<" inserted\n"; } else if (msg.port() == peer_offline){ int inpeer = msg.value(); //get all the connected nodes a disconnect them, plus let them know they've been disconnected set<int> connected = thegraph->getConnectedNodes(inpeer); set<int>::iterator sit; int count = 0; for ( sit=connected.begin() ; sit != connected.end(); sit++ ){ count++; thegraph->disconnect(inpeer, *sit); //disconnect them EvQ.push(makeDisConnectEvent(inpeer, *sit,currenttimefloat+count)); // enqueue messages to be output with just 1 millisecond delay //DisconnectionQueue.push(buildMessage(*sit, inpeer)); //enqueue a message saying peer "inpeer" disconnects from "*sit" } thegraph->offline(inpeer); if(VERBOSE) cout<<"node "<<msg.value()<<" removed\n"; //holdIn( active, Time(0.00f)); } else if (msg.port() == peer_connect){ int twonumbers, from, to; twonumbers = msg.value(); from = getPeerId(twonumbers); //first and second field encoding of the peers to = getMessageId(twonumbers); if(VERBOSE) cout<<"connecting "<<from<<" to "<< to<<"\n"; if(thegraph->connect(from,to)) EvQ.push(makeConnectEvent(from, to,currenttimefloat+1)); // enqueue message to be output with just 1 millisecond delay //ConnectionQueue.push(buildMessage(to, from, 1)); // enqueue a connection message : adding the TTL makes it different from a disconnect message, further down the road //holdIn( active, Time(0.00f)); } else if (msg.port() == peer_disconnect){ int twonumbers, from, to; twonumbers = msg.value(); from = getPeerId(twonumbers); //first and second field encoding of the peers to = getMessageId(twonumbers); if(VERBOSE) cout<<"disconnecting "<<from<<" and "<< to<<"\n"; if(thegraph->disconnect(from, to)) EvQ.push(makeDisConnectEvent(from, to,currenttimefloat+1));//DisconnectionQueue.push(twonumbers); // enqueue the original message to be re-output as confirmation that connection took place //holdIn( active, Time(0.00f)); } else if (msg.port() == inroute){ //routing=true; int inpeer, TTL, messageId; inpeer = getPeerId(msg.value()); TTL= getTTL(msg.value()); messageId = getMessageId(msg.value()); if(VERBOSE) cout<<"about to route a message from"<<inpeer<<"\n"; //get all the connected nodes and enqueue the "arrival of the message" event for all these new nodes //find the nodes connected to this one set<int> connected = thegraph->getConnectedNodes(inpeer); //if(VERBOSE) cout<<"loop for enqueuing nodes :"<<connected.size()<<" nodes to enqueue"; set<int>::iterator sit; //if(VERBOSE) cout << "connected nodes contains:"; for ( sit=connected.begin() ; sit != connected.end(); sit++ ){ //generate a random network delay: float delay = static_cast<float>(distribution().get()); if(VERBOSE) cout<<"enqueueing event for time = "<<currenttimefloat +delay*1000<<"\n"; //delay in milliseconds ! EvQ.push(makeNetworkEvent(messageId, *sit, TTL, currenttimefloat + (delay*1000))); //enqueue a network event with the "*sit" peer (the other parts are not used for now) //holdIn( active, Time(0.01f)); } } if (EvQ.empty()){ // this transition didn't enqueue anything if(VERBOSE) cout<<"LTS:Event queue is empty. Passivating."<<endl; passivate(); } else { //calculate time until next scheduled change : float remainingdelay = EvQ.top().time - currenttimefloat; //EvQ.top() is the next NetworkEvent to be output if(VERBOSE) cout<<"next change at (ms):"<<EvQ.top().time<<"time until next change (s):"<<remainingdelay/1000<<endl; // hold until then holdIn(active, Time(remainingdelay/1000)); // time remaining until next scheduled change //then it will be time for an internal transition... } /*/ TEST : no external transition unless we're passive if (this->state()==passive){ holdIn( active, Time(0,0,0,120)); //wait 120ms before doing something }*/ return *this ; }
/******************************************************************* * Function Name: externalFunction * Description: the Network gets input from outside ********************************************************************/ Model <SNetwork::externalFunction( const ExternalMessage &msg ){ //if(VERBOSE) cout<<"coucou\n"; // if ( this->state() == passive) // in fact all this should happen whatever the state ! TODO !! // { if (msg.port() == peer_online) { thegraph->online(msg.value()); //adds a node to the graph with the given value if(VERBOSE) cout<<"node "<<msg.value()<<" inserted\n"; //holdIn( active, Time(0.00f)); } else if (msg.port() == peer_offline){ thegraph->offline(msg.value()); if(VERBOSE) cout<<"node "<<msg.value()<<" removed\n"; //holdIn( active, Time(0.00f)); } else if (msg.port() == peer_connect){ int twonumbers, from, to; twonumbers = msg.value(); from = floor(twonumbers /1000); to = twonumbers%1000; if(VERBOSE) cout<<"connecting "<<from<<" to "<< to<<"\n"; thegraph->connect(from,to); //holdIn( active, Time(0.00f)); } else if (msg.port() == peer_disconnect){ int twonumbers, from, to; twonumbers = msg.value(); from = floor(twonumbers /1000); to = twonumbers%1000; if(VERBOSE) cout<<"disconnecting "<<from<<" and "<< to<<"\n"; thegraph->disconnect(from, to); //holdIn( active, Time(0.00f)); } else if (msg.port() == inroute){ //routing=true; int inpeer, TTL, messageId; inpeer = getPeerId(msg.value()); TTL= getTTL(msg.value()); messageId = getMessageId(msg.value()); if(VERBOSE) cout<<"LTS --- about to route a message from "<<inpeer<<"\n"; //get all the connected nodes and enqueue the "arrival of the message" event for all these new nodes //find the nodes connected to this one cout<<"LTS --- about to get Connected peers : \n"; /*thegraph->getConnectedNodes(inpeer); cout<<"getConnectedpeers (1) passed\n about to declare another intbag\n";*/ set<int> connected; //cout<<"ok--Intbag Declared----------------\nabout to get connected peers again"; connected = thegraph->getConnectedNodes(inpeer); //cout<<"ok--after connected peers----------------\n"; if(VERBOSE) cout<<"LTS --- loop for enqueuing nodes :"<<connected.size()<<" nodes to enqueue\n"; set<int>::iterator sit; if(VERBOSE) cout << "LTS --- connected nodes contains:"; for ( sit=connected.begin() ; sit != connected.end(); sit++ ){ if(VERBOSE) cout<<*sit<<";"; EvQ.push(makeNetworkEvent(messageId, *sit, TTL, 0.0f)); //enqueue a network event with the "*sit" peer (the other parts are not used for now) //holdIn( active, Time(0.01f)); } if(VERBOSE) cout<<endl; //} if (!EvQ.empty()) { // if we were or now are in the process of routing messages holdIn( active, Time(0.03f)); // we wait 0.03s to dequeue } else { holdIn( active, Time(0.00f)); // we just passivate immediately } return *this ; } }
/******************************************************************* * Function Name: externalFunction * Description: the router gets input from either the "outside" (a new messgae to route) or from the router (next step for routing) ********************************************************************/ Model &Gnutella::externalFunction( const ExternalMessage &msg ){ if ( this->state() == passive) { if (msg.port() == route_in) //new message to route { //expecting float values looking like 6,123 meaning route from peer 6 with msg id 123 (id<1000) //get the peerid, message id, generate new TTL, then put in "to output" variable // not a list ! [id, TTL, peer] if(VERBOSE) cout<<"Gnutella : new routing message : "<<msg.value()<<endl; int peerid = getPeerId(msg.value());// get originating peer (from value of external msg) if(VERBOSE)cout<<" peerid:"<<peerid<<endl; int id = getMessageId(msg.value()); // get message id if(VERBOSE)cout<<" message id:"<<id<<endl; //create "seen" list. The message ids are float values (that way we can generate them using a random function) // to create an empty list I use the default constructor, throught the shortcut of calling the [] operator. routingTable[id]; //creates empty set mapped to id routingTable[id].insert(peerid); // the new peer has now been visited (because the first thing will be to send himself the message !) // we need to propagate this message to the DB and route it in the network (separate issues) hitting = true; routing = true; //set the output values // from right, digits 1-3 are id, digits 4-6 are peerid, digit 7 is TTL exampel value : 6005123 = TTL=6, peerid 5, id = 123 nextOutputDB = buildMessage(id, peerid); nextOutputR =buildMessage(id, peerid, STANDARDTTL); //standardTTL is a constant defined in the h, should be a model parameter //if(VERBOSE) cout<<"next output:"<<nextOutputR<<endl; } else if (msg.port() == in_n){ //expecting value = TTL * 100 + peerid + id, where id is the decimal part (<1) if(VERBOSE) cout<<"Gnutella : message from the network routing loop... "<<msg.value()<<"\n"; long inval = msg.value(); //extract our 3 values using static functions from complexmessages.h int OldTTL = getTTL(inval); //if(VERBOSE)cout<<"old ttl:"<<OldTTL<<endl; int peerid = getPeerId(inval); //if(VERBOSE)cout<<" peerid:"<<peerid<<endl; int id = getMessageId(inval); //if(VERBOSE)cout<<" message id:"<<id<<endl; //check for already visited peer : search for "peerid" in set mapped to id in routing table set<long>::iterator finder = routingTable[id].find(peerid); if(finder==routingTable[id].end()){ //it's NOT in there //the unseen peer must get the message if(VERBOSE)cout<<" peerid:"<<peerid<<"unseen by msg id ="<<id<< endl; hitting = true; nextOutputDB = buildMessage(id, peerid); // we don't put in a TTL // the new peer has now been visited : we add him to the set of seen peers routingTable[id].insert(peerid); if(OldTTL>0){ // the unseen peer will also propagate the message because it still has some TTL routing=true; nextOutputR = buildMessage(id, peerid, OldTTL-1); //add the TTL for the routing msg if(VERBOSE)cout<<" message will be re-cycled TTL >0 "<< endl; } else { routing = false; } } else { if(VERBOSE)cout<<" peerid:"<<peerid<<"already visited by msg id ="<<id<< endl; hitting = false; routing = false; } } } //end if state is passive else{ cout<<"error: message received while in active state"<<endl; } // we have an instantaneous change back to the passive state (will output the next output values where relevant) holdIn( active, Time(0.01f)); return *this ; }