/* * Decompress the TCP data of an SKB. */ int tcp_decompress(__u8 *ippacket, __u8 *lzbuffer, qlz_state_decompress *state_decompress) { struct iphdr *iph = NULL; struct tcphdr *tcph = NULL; __u16 oldsize = 0, newsize = 0; /* Store old, and new size of the TCP data. */ __u8 *tcpdata = NULL; /* Starting location for the TCP data. */ char message[LOGSZ]; if (DEBUG_COMPRESSION == true) { sprintf(message, "[OpenNOP]: Entering into TCP DECOMPRESS \n"); logger(LOG_INFO, message); } if ((ippacket != NULL) && (NULL != state_decompress)) { // If the skb or state_decompress is NULL abort compression. iph = (struct iphdr *) ippacket; // Access ip header. memset(state_decompress, 0, sizeof(qlz_state_decompress)); if ((iph->protocol == IPPROTO_TCP)) { // If this is not a TCP segment abort compression. tcph = (struct tcphdr *) (((u_int32_t *) ippacket) + iph->ihl); // Access tcp header. oldsize = (__u16)(ntohs(iph->tot_len) - iph->ihl * 4) - tcph->doff * 4; tcpdata = (__u8 *) tcph + tcph->doff * 4; // Find starting location of the TCP data. if ((oldsize > 0) && (lzbuffer != NULL)) { newsize = qlz_decompress((char *) tcpdata, (char *) lzbuffer, state_decompress); memmove(tcpdata, lzbuffer, newsize); // Move decompressed data to packet. iph->tot_len = htons(ntohs(iph->tot_len) + (newsize - oldsize));// Fix packet length. __set_tcp_option((__u8 *) iph, 33, 3, 0); // Set compression flag to 0. /* tcph->seq = htonl(ntohl(tcph->seq) - 8000); // Decrease SEQ number. */ if (DEBUG_COMPRESSION == true) { sprintf( message, "[OpenNOP] Decompressing [%d] size of data to [%d] \n", oldsize, newsize); logger(LOG_INFO, message); } // return 1; // fruiz return amount of data expansion return newsize-oldsize; } } } return -1; }
/* * This sends a keep alive message to the specified IP. * It does not tag the packet with the Accelerator ID this * prevents the keepalive messages from recreating dead sessions * in remote Accelerators. */ void sendkeepalive (__u32 saddr, __u16 source, __u32 seq, __u32 daddr, __u16 dest, __u32 ack_seq){ char packet[BUFSIZE]; struct iphdr *iph = NULL; struct tcphdr *tcph = NULL; struct sockaddr_in sin, din; __u16 tcplen; memset(packet, 0, BUFSIZE); sin.sin_family = AF_INET; din.sin_family = AF_INET; sin.sin_port = source; din.sin_port = dest; sin.sin_addr.s_addr = saddr; din.sin_addr.s_addr = daddr; iph = (struct iphdr *)packet; iph->ihl = 5; // IP header length. iph->version = 4; // IP version 4. iph->tos = 0; // No TOS. iph->tot_len=htons(sizeof(struct iphdr) + sizeof(struct tcphdr)); // L3 + L4 header length. iph->id = 0; // What? iph->frag_off = 0; // No fragmenting. iph->ttl = 64; // Set a TTL. iph->protocol = IPPROTO_TCP; // TCP protocol. iph->check = 0; // No IP checksum yet. iph->saddr = saddr; // Source IP. iph->daddr = daddr; // Dest IP. tcph = (struct tcphdr *) (((u_int32_t *)iph) + iph->ihl); tcph->check = 0; // No TCP checksum yet. tcph->source = source; // Source TCP Port. tcph->dest = dest; // Destination TCP Port. tcph->seq = htonl(seq - 1); // Current SEQ minus one is used for TCP keepalives. tcph->ack_seq = htonl( ack_seq - 1); // Ummm not sure yet. tcph->res1 = 0; // Not sure. tcph->doff = 5; // TCP Offset. At least 5 if there are no TCP options. tcph->fin = 0; // FIN flag. tcph->syn = 0; // SYN flag. tcph->rst = 0; // RST flag. tcph->psh = 0; // PSH flag. tcph->ack = 1; // ACK flag. tcph->urg = 0; // URG flag. __set_tcp_option((__u8 *)iph,32,6,localID); // Add the Accelerator ID to this packet. tcplen = ntohs(iph->tot_len) - iph->ihl*4; tcph->check = 0; tcph->check = tcp_sum_calc(tcplen, (unsigned short *)&iph->saddr, (unsigned short *)&iph->daddr, (unsigned short *)tcph); iph->check = 0; iph->check = ip_sum_calc(iph->ihl*4, (unsigned short *)iph); if(sendto(rawsock, packet, ntohs(iph->tot_len), 0, (struct sockaddr *)&din, sizeof(din)) < 0){ printf("sendto() error\n"); } return; }
/* * Deoptimize the TCP data of an SKB. */ int tcp_deoptimize(pDeduplicator pd, __u8 *ippacket, __u8 *regenerated_packet) { struct iphdr *iph = NULL; struct tcphdr *tcph = NULL; __u16 oldsize = 0, newsize = 0; /* Store old, and new size of the TCP data. */ __u8 *tcpdata = NULL; /* Starting location for the TCP data. */ char message[LOGSZ]; UncompReturnStatus status; if (DEBUG_DEDUPLICATION1 == true) { sprintf(message, "[SDEDUP]: Entering into TCP DEOPTIMIZATION \n"); logger(LOG_INFO, message); } if ((ippacket != NULL)) { // If the skb or state_decompress is NULL abort compression. iph = (struct iphdr *) ippacket; // Access ip header. if ((iph->protocol == IPPROTO_TCP)) { // If this is not a TCP segment abort compression. if (DEBUG_DEDUPLICATION == true) { sprintf(message, "[SDEDUP]: IP Packet ID %u\n", ntohs(iph->id)); logger(LOG_INFO, message); } tcph = (struct tcphdr *) (((u_int32_t *) ippacket) + iph->ihl); // Access tcp header. oldsize = (__u16)(ntohs(iph->tot_len) - iph->ihl * 4) - tcph->doff* 4; tcpdata = (__u8 *) tcph + tcph->doff * 4; // Find starting location of the TCP data. if ((oldsize > 0) && (regenerated_packet != NULL)) { #ifdef BASIC if(deoptimize(tcpdata, oldsize, regenerated_packet, &newsize) == 2) return HASH_NOT_FOUND; #endif #ifdef ROLLING uncomp(pd,regenerated_packet, &newsize, tcpdata, oldsize, &status); if(status.code == UNCOMP_FP_NOT_FOUND) return HASH_NOT_FOUND; #endif memmove(tcpdata, regenerated_packet, newsize); // Move decompressed data to packet. iph->tot_len = htons(ntohs(iph->tot_len) + (newsize - oldsize));// Fix packet length. __set_tcp_option((__u8 *) iph, 31, 3, 0); // Set compression flag to 0. /* Bellido: change from decreasing seq number to changing most significant bit tcph->seq = htonl(ntohl(tcph->seq) - 8000); // Decrease SEQ number. */ tcph->seq = htonl(ntohl(tcph->seq) ^ 1 << 31 ); // Change most significant bit if (DEBUG_DEDUPLICATION == true) { sprintf( message, "[SDEDUP]: Decompressing [%d] size of data to [%d] \n", oldsize, newsize); logger(LOG_INFO, message); } // return OK; // fruiz return amount of expanded data if (newsize >= oldsize) return newsize-oldsize; else return ERROR; } } } if (DEBUG_DEDUPLICATION == true) { sprintf( message, "[SDEDUP]: Packet NULL\n"); logger(LOG_INFO, message); } return ERROR; }
/* * Optimize the TCP data of an SKB. */ unsigned int tcp_optimize(pDeduplicator pd, __u8 *ippacket, __u8 *buffered_packet) { struct iphdr *iph = NULL; struct tcphdr *tcph = NULL; __u16 oldsize = 0, newsize = 0; /* Store old, and new size of the TCP data. */ __u8 *tcpdata = NULL; /* Starting location for the TCP data. */ char message[LOGSZ]; int compressed; if (DEBUG_DEDUPLICATION == true) { sprintf(message, "[DEDUP]: Entering into TCP OPTIMIZATION \n"); logger(LOG_INFO, message); } // If the skb or state_compress is NULL abort compression. if ((ippacket != NULL) && (deduplication == true)) { iph = (struct iphdr *) ippacket; // Access ip header. if ((iph->protocol == IPPROTO_TCP)) { // If this is not a TCP segment abort deduplication. tcph = (struct tcphdr *) (((u_int32_t *) ippacket) + iph->ihl); oldsize = (__u16)(ntohs(iph->tot_len) - iph->ihl * 4) - tcph->doff * 4; tcpdata = (__u8 *) tcph + tcph->doff * 4; // Find starting location of the TCP data. if (oldsize > 0) { // Only compress if there is any data. if (DEBUG_DEDUPLICATION == true) { sprintf(message, "[DEDUP]: IP packet ID: %u\n", ntohs(iph->id)); logger(LOG_INFO, message); } newsize = (oldsize * 2); if (DEBUG_DEDUPLICATION1 == true) { sprintf(message, "[DEDUP]: Begin deduplication.\n"); logger(LOG_INFO, message); } #ifdef BASIC optimize(tcpdata, oldsize, buffered_packet, &newsize); #endif #ifdef ROLLING dedup(pd, tcpdata, oldsize, buffered_packet, &newsize); #endif compressed = newsize < oldsize; if (DEBUG_DEDUPLICATION == true) { sprintf(message, "[DEDUP]: OLD SIZE: %u \t NEW SIZE: %u\n", oldsize, newsize); logger(LOG_INFO, message); } if(compressed){ if (DEBUG_DEDUPLICATION == true) { sprintf(message, "[DEDUP]: IP packet %u COMPRESSED\n", ntohs(iph->id)); logger(LOG_INFO, message); } memmove(tcpdata, buffered_packet, newsize);// Move compressed data to packet. // Set the ip packet and the TCP options iph->tot_len = htons(ntohs(iph->tot_len) - (oldsize - newsize));// Fix packet length. __set_tcp_option((__u8 *) iph, 31, 3, 1); // Set compression flag. /* Bellido: change from increasing seq number to changing most significant bit tcph->seq = htonl(ntohl(tcph->seq) + 8000); // Increase SEQ number. */ tcph->seq = htonl(ntohl(tcph->seq) ^ 1 << 31 ); // Change most significant bit } if (DEBUG_DEDUPLICATION == true) { sprintf(message, "[DEDUP]: Leaving TCP OPTIMIZATION \n"); logger(LOG_INFO, message); } } } } // fruiz return amount of redundancy elimination if (compressed) return oldsize-newsize; else return 0; }
int fetcher_callback(struct nfq_q_handle *hq, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { u_int32_t id = 0; struct iphdr *iph = NULL; struct tcphdr *tcph = NULL; struct session *thissession = NULL; struct packet *thispacket = NULL; struct nfqnl_msg_packet_hdr *ph; struct timeval tv; __u32 largerIP, smallerIP, remoteID; __u16 largerIPPort, smallerIPPort, mms; int ret; int incomingQueueNum; unsigned char *originalpacket = NULL; char strIP[20]; // for debugging purposes char saddr[INET_ADDRSTRLEN]; char daddr[INET_ADDRSTRLEN]; ph = nfq_get_msg_packet_hdr(nfa); if (ph) { id = ntohl(ph->packet_id); } ret = nfq_get_payload(nfa, &originalpacket); if (servicestate >= RUNNING) { iph = (struct iphdr *) originalpacket; thefetcher.metrics.bytesin += ntohs(iph->tot_len); /* We need to double check that only TCP packets get accelerated. */ /* This is because we are working from the Netfilter QUEUE. */ /* User could QUEUE UDP traffic, and we cannot accelerate UDP. */ if ((iph->protocol == IPPROTO_TCP) && (id != 0)) { tcph = (struct tcphdr *) (((u_int32_t *) originalpacket) + iph->ihl); // for debugging purpose inet_ntop(AF_INET, &iph->saddr, saddr, INET_ADDRSTRLEN); inet_ntop(AF_INET, &iph->daddr, daddr, INET_ADDRSTRLEN); /* Check what IP address is larger. */ sort_sockets(&largerIP, &largerIPPort, &smallerIP, &smallerIPPort, iph->saddr, tcph->source, iph->daddr, tcph->dest); // remoteID = (__u32) __get_tcp_option((__u8 *)originalpacket,32); if (__get_tcp_option((__u8 *)originalpacket,32) ) { unsigned char *tcpdata = (unsigned char *) tcph + tcph->doff * 4; // Find starting location of the TCP data. unsigned int incLen = (__u16)(ntohs(iph->tot_len) - iph->ihl * 4) - tcph->doff * 4; if (incLen < sizeof(OpennopHeader)) { LOGERROR(lc_fetcher, "detected opennop option but incoming TCP data length less than opennop header length!!!!"); return nfq_set_verdict(hq, id, NF_DROP,0,NULL); } pOpennopHeader oh = (pOpennopHeader) tcpdata; remoteID = oh->opennopID; incomingQueueNum = oh->queuenum; if (oh->pattern != OPENNOP_PATTERN) { LOGERROR(lc_fetcher, "option 32 found but bad pattern!!!"); return nfq_set_verdict(hq, id, NF_DROP,0,NULL); } } else remoteID = 0; inet_ntop(AF_INET, &remoteID, strIP, INET_ADDRSTRLEN); //LOGDEBUG(lc_fetcher, "The accellerator ID is:%s", strIP); if (remoteID == 0) { LOGTRACE(lc_fetcher, "Packet from CLIENT: SYN=%d/FIN=%d/ACK=%d/RST=%d, %s:%d->%s:%d, IP_Id=%d, NFQ_Id=%d, TCP_seq=%u, ACK_seq=%u, Total_len=%d, TCP_hlen=%d, IP_hlen=%d, Data_len=%d", tcph->syn, tcph->fin, tcph->ack, tcph->rst, saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest), ntohs(iph->id), id, ntohl(tcph->seq), ntohl(tcph->ack_seq), ntohs(iph->tot_len), tcph->doff * 4, iph->ihl * 4, ntohs(iph->tot_len) - tcph->doff * 4 - iph->ihl * 4); } else { LOGTRACE(lc_fetcher, "Packet from %s: SYN=%d/FIN=%d/ACK=%d/RST=%d, %s:%d->%s:%d, IP_Id=%d, NFQ_Id=%d, TCP_seq=%u, ACK_seq=%u, Total_len=%d, TCP_hlen=%d, IP_hlen=%d, Data_len=%d", strIP, tcph->syn, tcph->fin, tcph->ack, tcph->rst, saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest), ntohs(iph->id), id, ntohl(tcph->seq), ntohl(tcph->ack_seq), ntohs(iph->tot_len), tcph->doff * 4, iph->ihl * 4, ntohs(iph->tot_len) - tcph->doff * 4 - iph->ihl * 4); } thissession = getsession(largerIP, largerIPPort, smallerIP, smallerIPPort); // Check for an outstanding syn. // if (thissession != NULL) { // LOGDEBUG(lc_sesman_check, "****** [SESSION MANAGER] LargerIPseq: %u SmallerIPseq %u, TCP_seq=%u", thissession->largerIPseq, thissession->smallerIPseq, ntohl(tcph->seq)); // } /* Check if this a SYN packet to identify a new session. */ /* This packet will not be placed in a work queue, but */ /* will be accepted here because it does not have any data. */ //if ((tcph->syn == 1) && (tcph->ack == 0)) { if (tcph->syn == 1) { // // SYN segment // if (tcph->ack == 0) { if (remoteID == 0) { LOGDEBUG(lc_fetcher, "SYN from CLIENT: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); } else { LOGDEBUG(lc_fetcher, "SYN from %s: %s:%d->%s:%d", strIP, saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); } } else { if (remoteID == 0) { LOGDEBUG(lc_fetcher, "SYN+ACK from CLIENT: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); } else { LOGDEBUG(lc_fetcher, "SYN+ACK from %s: %s:%d->%s:%d", strIP, saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); } } if (thissession == NULL) { if (remoteID != 0) thissession = insertsession(largerIP, largerIPPort, smallerIP, smallerIPPort, incomingQueueNum); // Insert into sessions list. else thissession = insertsession(largerIP, largerIPPort, smallerIP, smallerIPPort, -1); // Insert into sessions list. if (remoteID == 0) { LOGDEBUG(lc_fetcher, "New session from CLIENT created: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ) } else { LOGDEBUG(lc_fetcher, "New session from %s created: %s:%d->%s:%d", strIP, saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ) }; } /* We need to check for NULL to make sure */ /* that a record for the session was created */ if (thissession != NULL) { gettimeofday(&tv,NULL); // Get the time from hardware. thissession->lastactive = tv.tv_sec; // Update the session timestamp. sourceisclient(largerIP, iph, thissession, tcph->ack == 0); updateseq(largerIP, iph, tcph, thissession); updateseqnumber(largerIP, iph, tcph, thissession); if (remoteID == 0) { // Accelerator ID was not found. mms = __get_tcp_option((__u8 *)originalpacket,2); if (mms > 68) { if (__set_tcp_option((__u8 *)originalpacket,2,4,mms - 68) == -1) {// Reduce the MSS. LOGERROR(lc_fetcher, "Cannot reduce MSS in 68, fetcher.c, packet is a SYN, IP datagram ID %x, current value of TCP doff %d",ntohs(iph->id), tcph->doff); } if (__set_tcp_option((__u8 *)originalpacket,32,3,1) == -1) { // Add the Accelerator ID to this packet. LOGERROR(lc_fetcher, "Cannot set opennop option to 1, fetcher.c, packet is a SYN, IP datagram ID %x, current value of TCP doff %d",ntohs(iph->id), tcph->doff); } else { unsigned char *tcpdata = (unsigned char *) tcph + tcph->doff * 4; // Find starting location of the TCP data. pOpennopHeader oh = (pOpennopHeader) tcpdata; oh->opennopID = localID; oh->seqNo = 0; oh->compression = 0; oh->deduplication = 0; oh->reasonForNoOptimization = NOT_RELEVANT; oh->pattern = OPENNOP_PATTERN; oh->queuenum = thissession->queue; iph->tot_len = htons(ntohs(iph->tot_len)+sizeof(OpennopHeader)); LOGTRACE(lc_fetcher, "Adding opennop header to SYN packet: IP total length=%d",ntohs(iph->tot_len)); } saveacceleratorid(largerIP, localID, iph, thissession); /* * Changing anything requires the IP and TCP * checksum to need recalculated. */ checksum(originalpacket); } } else { // Accelerator ID was found. //LOGDEBUG(lc_fetcher, "New session from %s created: %s:%d->%s:%d", strIP, saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); if (__set_tcp_option((__u8 *)originalpacket,32,3,0) == -1) { LOGERROR(lc_fetcher, "Cannot set opennop option to 0, fetcher.c, packet is a SYN, IP datagram ID %x, current value of TCP doff %d",ntohs(iph->id), tcph->doff); } else iph->tot_len = htons(ntohs(iph->tot_len)-sizeof(OpennopHeader)); checksum(originalpacket); saveacceleratorid(largerIP, remoteID, iph, thissession); } if (tcph->ack == 0) { thissession->state = TCP_SYN_SENT; LOGDEBUG(lc_fetcher, "Session state set to TCP_SYN_SENT"); } else { thissession->state = TCP_ESTABLISHED; LOGDEBUG(lc_fetcher, "Session state set to TCP_ESTABLISHED"); } } /* Before we return let increment the packets counter. */ thefetcher.metrics.packets++; /* This is the last step for a SYN packet. */ /* accept all SYN packets. */ return nfq_set_verdict(hq, id, NF_ACCEPT, ntohs(iph->tot_len), (unsigned char *)originalpacket); // } else if (tcph->rst == 1) { // // RESET segment // // LOGDEBUG(lc_fetcher, "Session RESET %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest)); // clearsession(thissession); // fruiz // // thissession = NULL; /* Before we return let increment the packets counter. */ // thefetcher.metrics.packets++; // return nfq_set_verdict(hq, id, NF_ACCEPT, 0, NULL); // } else if (tcph->fin == 1) { // // // // // FIN segment // // // LOGDEBUG(lc_fetcher, "FIN packet: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest)); // if (thissession != NULL) { // switch (thissession->state) { // case TCP_ESTABLISHED: // thissession->state = TCP_CLOSING; // LOGDEBUG(lc_fetcher, "Session half closed: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest)); // break; // case TCP_CLOSING: // clearsession(thissession); // LOGDEBUG(lc_fetcher, "Session full closed: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest)); // break; // } // } // // /* Before we return let increment the packets counter. */ // thefetcher.metrics.packets++; // LOGDEBUG(lc_fetcher, "hq=%d, id=%d", hq, id); // int res = nfq_set_verdict(hq, id, NF_ACCEPT, ntohs(iph->tot_len), (unsigned char *)originalpacket); // LOGDEBUG(lc_fetcher, "Returning FIN packet %d", res); // //return nfq_set_verdict(hq, id, NF_ACCEPT, 0, NULL); // //return nfq_set_verdict(hq, id, NF_ACCEPT, ntohs(iph->tot_len), (unsigned char *)originalpacket); // return res; } else { // // DATA or FIN segment // if (thissession != NULL) { // DATA segment in an active session //LOGDEBUG(lc_sesman_check, "[SESSION MANAGER] LargerIPseq: %u SmallerIPseq %u", thissession->largerIPseq, thissession->smallerIPseq); gettimeofday(&tv,NULL); // Get the time from hardware. thissession->lastactive = tv.tv_sec; // Update the active timer. thissession->deadcounter = 0; // Reset the dead counter. if (__get_tcp_option((__u8 *)originalpacket,32) == 2) { // Keepalive, can drop LOGDEBUG(lc_fetcher, "Received keepalive: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); return nfq_set_verdict(hq, id, NF_DROP,0,NULL); } thispacket = get_freepacket_buffer(); if (thispacket != NULL){ save_packet(thispacket,hq, id, ret, (__u8 *)originalpacket, thissession); if (remoteID == 0){ LOGTRACE(lc_fetcher, "Packet sent to optimize"); optimize_packet(thissession->queue, thispacket); } else { LOGTRACE(lc_fetcher, "Packet sent to deoptimize"); deoptimize_packet(thissession->queue, thispacket); } } else { LOGERROR(lc_fetcher, "Failed getting packet buffer for processing"); } /* Before we return let increment the packets counter. */ thefetcher.metrics.packets++; return 0; } else { // DATA segment and no active session exists int data_len = ntohs(iph->tot_len) - tcph->doff * 4 - iph->ihl * 4; if (data_len > 0) { LOGDEBUG(lc_fetcher, "No session found for: SYN=%d/FIN=%d/ACK=%d/RST=%d, %s:%d->%s:%d, Opt_ID=%s, IP_Id=%d, NFQ_Id=%d, Total_len=%d, TCP_hlen=%d, IP_hlen=%d, Data_len=%d", tcph->syn, tcph->fin, tcph->ack, tcph->rst, saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest), strIP, ntohs(iph->id), id, ntohs(iph->tot_len), tcph->doff * 4, iph->ihl * 4, ntohs(iph->tot_len) - tcph->doff * 4 - iph->ihl * 4); } /* We only want to create new sessions for active sessions. */ /* This means we exclude anything accept ACK packets. */ if (tcph->ack == 1) { if (remoteID != 0) { // Detected remote Accelerator so it is safe to add this session. thissession = insertsession(largerIP, largerIPPort, smallerIP, smallerIPPort, incomingQueueNum); // Insert into sessions list. if (thissession != NULL) { // Test to make sure the session was added. LOGDEBUG(lc_fetcher, "Created NEW session for: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); thissession->state = TCP_ESTABLISHED; saveacceleratorid(largerIP, remoteID, iph, thissession); thispacket = get_freepacket_buffer(); if (thispacket != NULL){ save_packet(thispacket,hq, id, ret, (__u8 *)originalpacket, thissession); updateseqnumber(largerIP, iph, tcph, thissession); //Update the stored TCP sequence number deoptimize_packet(thissession->queue, thispacket); } else { LOGERROR(lc_fetcher, "Failed getting packet buffer for deoptimization."); } /* Before we return let increment the packets counter. */ thefetcher.metrics.packets++; return 0; } else { LOGERROR(lc_fetcher, "Failed to create session for: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); } } } /* Before we return let increment the packets counter. */ thefetcher.metrics.packets++; //LOGERROR(lc_fetcher, "Unknown packet: %s:%d->%s:%d", saddr, ntohs(tcph->source), daddr, ntohs(tcph->dest) ); return nfq_set_verdict(hq, id, NF_ACCEPT, ntohs(iph->tot_len), (unsigned char *)originalpacket); } } } else { /* Packet was not a TCP Packet or ID was 0. */
/* * Compresses the TCP data of an SKB. */ unsigned int tcp_compress(__u8 *ippacket, __u8 *lzbuffer, qlz_state_compress *state_compress) { struct iphdr *iph = NULL; struct tcphdr *tcph = NULL; __u16 oldsize = 0, newsize = 0; /* Store old, and new size of the TCP data. */ __u8 *tcpdata = NULL; /* Starting location for the TCP data. */ char message[LOGSZ]; if (DEBUG_COMPRESSION == true) { sprintf(message, "[OpenNOP]: Entering into TCP COMPRESS \n"); logger(LOG_INFO, message); } // If the skb or state_compress is NULL abort compression. if ((ippacket != NULL) && (NULL != state_compress) && (compression == true)) { iph = (struct iphdr *) ippacket; // Access ip header. memset(state_compress, 0, sizeof(qlz_state_compress)); if ((iph->protocol == IPPROTO_TCP)) { // If this is not a TCP segment abort compression. tcph = (struct tcphdr *) (((u_int32_t *) ippacket) + iph->ihl); oldsize = (__u16)(ntohs(iph->tot_len) - iph->ihl * 4) - tcph->doff * 4; tcpdata = (__u8 *) tcph + tcph->doff * 4; // Find starting location of the TCP data. if (DEBUG_COMPRESSION == true) { sprintf(message, "Compression: Original TCP data length is: %u\n", oldsize); logger(LOG_INFO, message); } if (oldsize > 0) { // Only compress if there is any data. newsize = (oldsize * 2); if (lzbuffer != NULL) { if (DEBUG_COMPRESSION == true) { sprintf(message, "Compression: Begin compression.\n"); logger(LOG_INFO, message); } newsize = qlz_compress((char *) tcpdata, (char *) lzbuffer, oldsize, state_compress); } else { if (DEBUG_COMPRESSION == true) { sprintf(message, "Compression: lzbuffer was NULL!\n"); logger(LOG_INFO, message); } } if (DEBUG_COMPRESSION == true) { sprintf(message, "Compression: New TCP data length is: %u\n", newsize); logger(LOG_INFO, message); } if (newsize < oldsize) { memmove(tcpdata, lzbuffer, newsize); // Move compressed data to packet. //pskb_trim(skb,skb->len - (oldsize - newsize)); // Remove extra space from skb. iph->tot_len = htons(ntohs(iph->tot_len) - (oldsize - newsize));// Fix packet length. __set_tcp_option((__u8 *) iph, 31, 3, 1); // Set compression flag. tcph->seq = htonl(ntohl(tcph->seq) + 8000); // Increase SEQ number. if (DEBUG_COMPRESSION == true) { sprintf(message, "Compressing [%d] size of data to [%d] \n", oldsize, newsize); logger(LOG_INFO, message); } } if (DEBUG_COMPRESSION == true) { sprintf(message, "[OpenNOP]: Leaving TCP COMPRESS \n"); logger(LOG_INFO, message); } } } } return 1; }
/* * This sends a keep alive message to the specified IP. * It does not tag the packet with the Accelerator ID this * prevents the keepalive messages from recreating dead sessions * in remote Accelerators. */ void sendkeepalive (__u32 saddr, __u16 source, __u32 seq, __u32 daddr, __u16 dest, __u32 ack_seq){ char packet[BUFSIZE]; struct iphdr *iph = NULL; struct tcphdr *tcph = NULL; //struct sockaddr_in sin; struct sockaddr_in din; __u16 tcplen; memset(packet, 0, BUFSIZE); //sin.sin_family = AF_INET; din.sin_family = AF_INET; //sin.sin_port = source; din.sin_port = dest; //sin.sin_addr.s_addr = saddr; din.sin_addr.s_addr = daddr; iph = (struct iphdr *)packet; iph->ihl = 5; // IP header length. iph->version = 4; // IP version 4. iph->tos = 0; // No TOS. iph->tot_len=htons(sizeof(struct iphdr) + sizeof(struct tcphdr)); // L3 + L4 header length. iph->id = 0; // What? iph->frag_off = 0; // No fragmenting. iph->ttl = 64; // Set a TTL. iph->protocol = IPPROTO_TCP; // TCP protocol. iph->check = 0; // No IP checksum yet. iph->saddr = saddr; // Source IP. iph->daddr = daddr; // Dest IP. tcph = (struct tcphdr *) (((u_int32_t *)iph) + iph->ihl); tcph->check = 0; // No TCP checksum yet. tcph->source = source; // Source TCP Port. tcph->dest = dest; // Destination TCP Port. tcph->seq = htonl(seq - 1); // Current SEQ minus one is used for TCP keepalives. tcph->ack_seq = htonl( ack_seq - 1); // Ummm not sure yet. tcph->res1 = 0; // Not sure. tcph->doff = 5; // TCP Offset. At least 5 if there are no TCP options. tcph->fin = 0; // FIN flag. tcph->syn = 0; // SYN flag. tcph->rst = 0; // RST flag. tcph->psh = 0; // PSH flag. tcph->ack = 1; // ACK flag. tcph->urg = 0; // URG flag. if (__set_tcp_option((__u8 *)iph,32,3,2) == -1) { // Add the Accelerator ID to this packet. LOGDEBUG(lc_sesman, "Sessioncleanup: Cannot add accelerator ID, sessioncleanup.c, IP datagram ID %x, current value of TCP doff %d",ntohs(iph->id), tcph->doff); } else { unsigned char *tcpdata = (unsigned char *) tcph + tcph->doff * 4; // Find starting location of the TCP data. pOpennopHeader oh = (pOpennopHeader) tcpdata; oh->opennopID = localID; oh->seqNo = 0; oh->compression = 0; oh->deduplication = 0; oh->reasonForNoOptimization = NOT_RELEVANT; oh->queuenum = 0; oh->pattern = OPENNOP_PATTERN; iph->tot_len = htons(ntohs(iph->tot_len)+sizeof(OpennopHeader)); } tcplen = ntohs(iph->tot_len) - iph->ihl*4; tcph->check = 0; tcph->check = tcp_sum_calc(tcplen, (unsigned short *)&iph->saddr, (unsigned short *)&iph->daddr, (unsigned short *)tcph); iph->check = 0; iph->check = ip_sum_calc(iph->ihl*4, (unsigned short *)iph); if(sendto(rawsock, packet, ntohs(iph->tot_len), 0, (struct sockaddr *)&din, sizeof(din)) < 0){ printf("sendto() error\n"); } return; }