⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.cpp

📁 *** *** *** *** *** *** *** *** *** *** *** *** *** * assniffer v0.1 alpha, Copyright (C) 2004, Coc
💻 CPP
字号:
/*
    assniffer - tcp.cpp (TCP connection analysis)
    Copyright (C) 2004 Cockos Incorporated

    assniffer is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    assniffer is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with assniffer; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "platform.h"

#include "pcap.h"
#include "../WDL/ptrlist.h"
#include "../WDL/queue.h"
#include "http.h"
#include "tcp.h"

#define TWINDOW_SIZE 65536
#define CONNECTION_TIMEOUT 15 // seconds



class TCPCtx // monitors a TCP connection
{
public:
  TCPCtx(unsigned int src_ip, unsigned int dest_ip, unsigned short src_port, unsigned short dest_port);
  ~TCPCtx();
  void flushReplyBufs();
  void flushReqBufs();
  int onPacket(int dir, IP_header *iphdr, TCP_header *tcphdr, unsigned char *payload, int payload_len);

  HTTP_context *m_http;

  // if a reply comes in and it's replybuf_window_min, we just move 
  // replybuf_window_in up, and directly add the data.
  // otherwise, if it's between min and max, we add it in.
  // if it's >= max, we append it to replybuf, moving replybuf_window_max up,
  // and if we have to, we move min up, and copy that old data.
  // whenever we move up min, we should zero it out, too.
  // this shoudl be redone and we should track which pieces are missing, too.
  // oh well, TODO or something
  // also need to flush on timeout or on fins.

  WDL_Queue replybuf;
  unsigned char replybuf_window[TWINDOW_SIZE];
  unsigned int replybuf_window_min, replybuf_window_max;
  WDL_Queue reqbuf; 
  unsigned char reqbuf_window[TWINDOW_SIZE];
  unsigned int reqbuf_window_min, reqbuf_window_max;

  unsigned int m_src_ip, m_dest_ip;
  unsigned short m_src_port, m_dest_port;
  int m_had_fin;
  time_t m_last_time;
  int m_concnt;
};



TCPCtx::TCPCtx(unsigned int src_ip, unsigned int dest_ip, unsigned short src_port, unsigned short dest_port)
{
  m_concnt=0;
  m_src_ip=src_ip;
  m_dest_ip=dest_ip;
  m_src_port=src_port;
  m_dest_port=dest_port;
  m_had_fin=0;
  replybuf_window_min=replybuf_window_max=0;
	reqbuf_window_min=reqbuf_window_max=0;
  time(&m_last_time);
  m_http=0;
}

TCPCtx::~TCPCtx()
{
  if (m_http) delete m_http;
  m_http=0;
}

void TCPCtx::flushReplyBufs()
{
  if (replybuf_window_max > replybuf_window_min)
  {
    for (;replybuf_window_min < replybuf_window_max; replybuf_window_min++)
      replybuf.Add(&replybuf_window[replybuf_window_min & (TWINDOW_SIZE-1)],1);
  }
}

void TCPCtx::flushReqBufs()
{
  if (reqbuf_window_max > reqbuf_window_min)
  {
    for (;reqbuf_window_min < reqbuf_window_max; reqbuf_window_min++)
      reqbuf.Add(&reqbuf_window[reqbuf_window_min & (TWINDOW_SIZE-1)],1);
  }
}


int TCPCtx::onPacket(int dir, IP_header *iphdr, TCP_header *tcphdr, unsigned char *payload, int payload_len)
{
  if (tcphdr)
  {
    unsigned int seq=ntohl(tcphdr->sequence);
    if (tcphdr->th_flags & TH_SYN)
    {
      if (dir > 0) 
      {          
			  flushReqBufs();
		    reqbuf_window_min=reqbuf_window_max=seq+1;
      }
      else
      {
        //printf("got SYN from server, this should happen once per connection, you'd think (%u)\n",seq);
        flushReplyBufs();
        replybuf_window_min=replybuf_window_max=seq+1;
      }
    }

    if (payload_len>0)//else
    {
      if (dir > 0)
      {
        if (!reqbuf_window_min) 
        {
          reqbuf_window_min=reqbuf_window_max=seq;
        }

        if (seq == reqbuf_window_min)
        {
          //printf("got an in-order request payload (%u->%u %d bytes)\n",seq,seq+payload_len,payload_len);
          if (payload_len > 0) reqbuf.Add(payload,payload_len);
          reqbuf_window_min += payload_len;
          if (reqbuf_window_max < reqbuf_window_min) reqbuf_window_max=reqbuf_window_min;
        }
        else if (seq > reqbuf_window_min && seq+payload_len < reqbuf_window_max)
        {
          int x;
          for (x = 0; x < payload_len; x++)
            reqbuf_window[(seq+x) & (TWINDOW_SIZE-1)]=payload[x];
        }
        else if (seq > reqbuf_window_min && seq+payload_len >= reqbuf_window_max && seq < reqbuf_window_max + TWINDOW_SIZE)
        {
          if ((seq+payload_len)-reqbuf_window_min > TWINDOW_SIZE)
          {
            unsigned int endp = seq+payload_len - TWINDOW_SIZE;
            if (endp > reqbuf_window_min  + TWINDOW_SIZE) endp = reqbuf_window_min + TWINDOW_SIZE;

            for (;reqbuf_window_min < endp; reqbuf_window_min++)
              reqbuf.Add(&reqbuf_window[reqbuf_window_min & (TWINDOW_SIZE-1)],1);
          }

          int x;
          for (x = 0; x < payload_len; x ++)
          {
            reqbuf_window[(seq+x)&(TWINDOW_SIZE-1)]=payload[x];
          }
          reqbuf_window_max=seq+payload_len;
        }
      }
      else
      {
        if (!replybuf_window_min) 
        {
          //printf("replybuf_window_min=0, setting seq to %u\n",seq);
          replybuf_window_min=replybuf_window_max=seq;
        }

        if (seq == replybuf_window_min)
        {
          //printf("got an in-order reply payload (%u->%u %d bytes,  %dboo)\n",seq,seq+payload_len,payload_len,tcphdr->th_offs);
          if (payload_len > 0) replybuf.Add(payload,payload_len);
          replybuf_window_min += payload_len;
          if (replybuf_window_max < replybuf_window_min) replybuf_window_max=replybuf_window_min;
        }
        else if (seq > replybuf_window_min && seq+payload_len < replybuf_window_max)
        {
          //printf("this sux\n");
          int x;
          for (x = 0; x < payload_len; x++)
            replybuf_window[(seq+x) & (TWINDOW_SIZE-1)]=payload[x];
        }
        else if (seq > replybuf_window_min && seq+payload_len >= replybuf_window_max && seq < replybuf_window_max + TWINDOW_SIZE) // should use the window field of the TCP header here (and above), but oh well
        {
          //printf("this also sux (seq=%u, replybuf_window_min=%u)\n",seq,replybuf_window_min);
          if ((seq+payload_len)-replybuf_window_min > TWINDOW_SIZE)
          {
            unsigned int endp = seq+payload_len - TWINDOW_SIZE;
            if (endp > replybuf_window_min  + TWINDOW_SIZE) endp = replybuf_window_min + TWINDOW_SIZE;

            for (;replybuf_window_min < endp; replybuf_window_min++)
              replybuf.Add(&replybuf_window[replybuf_window_min & (TWINDOW_SIZE-1)],1);
          }

          int x;
          for (x = 0; x < payload_len; x ++)
          {
            replybuf_window[(seq+x)&(TWINDOW_SIZE-1)]=payload[x];
          }
          replybuf_window_max=seq+payload_len;
        }
      }
    }
    if (tcphdr->th_flags & TH_FIN)
    {
      m_had_fin |= dir>0 ? 1 : 2;
      if (dir < 0) flushReplyBufs();
      if (dir > 0) flushReqBufs();
    }
  }

  while (replybuf.Available() > 0)
  {
    int tryagain=0;

    if (!m_http) m_http = new HTTP_context(m_concnt++);

    if (!m_http->m_hasfoundget && reqbuf.Available()>0)
    {
      int l=m_http->onRequestStream((unsigned char *)reqbuf.Get(),reqbuf.Available());
      if (l>0)
      {
        reqbuf.Advance(l);
        reqbuf.Compact();
      }
      if (m_http->m_fail) return 1;
    }

    if (m_http->m_hasfoundget)
    {
      int l=m_http->onReplyData((unsigned char *)replybuf.Get(),replybuf.Available());       
      if (l > 0)
      {
        replybuf.Advance(l);
        replybuf.Compact();
        tryagain++;
      }
    }

    if (m_http->m_fail) return 1;

    if (m_http->isDone()) 
    {
      delete m_http;
      m_http=0;
      tryagain++;
    }

    if (!tryagain) break;
  }

  return (m_http && m_http->m_fail) || m_had_fin==3;
}





///////////////////////////////////////////////

static WDL_PtrList<TCPCtx> conlist;

void handle_tcp(IP_header *iphdr, TCP_header *tcphdr, unsigned char *payload, int payload_len)
{
  int x;

  time_t now;
  time(&now);

  for (x = 0; x < conlist.GetSize(); x ++)
  {
    TCPCtx *t=conlist.Get(x);
    if (now - t->m_last_time > CONNECTION_TIMEOUT)
    {
      t->flushReplyBufs();
      t->flushReqBufs();
      t->onPacket(-1,NULL,NULL,NULL,0);
      delete t;
      conlist.Delete(x--);
      //printf("Timed out connection\n");
    }
  }

  for (x = 0; x < conlist.GetSize(); x ++)
  {
    TCPCtx *t=conlist.Get(x);
    int dir=0;
    if (t->m_dest_ip == iphdr->dest_addr &&
        t->m_src_ip == iphdr->source_addr &&
        t->m_dest_port == tcphdr->dest_port &&
        t->m_src_port == tcphdr->source_port)
    {
      dir=1;
    }
    else  if (t->m_src_ip == iphdr->dest_addr &&
        t->m_dest_ip == iphdr->source_addr &&
        t->m_src_port == tcphdr->dest_port &&
        t->m_dest_port == tcphdr->source_port)
    {
      dir=-1;
    }


    if (dir)
    {
      //printf("got %d byte ethernet packet off wire (%d byte TCP payload)!\n",orig_len,payload_len);
      t->m_last_time = now;

      if (t->onPacket(dir,iphdr,tcphdr,payload,payload_len))
      {
        conlist.Delete(x);
        delete t;
    //    printf("Fin'd connection\n");
      }
      return;
    }
  }

  // woo, new connection
  if (tcphdr->th_flags & TH_SYN)
  {
    TCPCtx *ctx = new TCPCtx(iphdr->source_addr,iphdr->dest_addr,tcphdr->source_port,tcphdr->dest_port);
    ctx->reqbuf_window_min=ctx->reqbuf_window_max=ntohl(tcphdr->sequence)+1;
    conlist.Add(ctx);
  //  printf("Added connection (%d)\n",conlist.GetSize());
  }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -