/*
    ettercap -- dissector portmap

    Copyright (C) 2001  ALoR <alor@users.sourceforge.net>, NaGA <crwm@freemail.it>

    This program 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.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    $Id: ec_dissector_portmap.c,v 1.3 2002/04/12 15:59:15 alor Exp $
*/


#include "include/ec_main.h"

#include "include/ec_dissector.h"
#include "include/ec_inet_structures.h"

//#define MAP_LEN 20
#define XID 0
#define PROG 1
#define PROTO 2
#define VER 3

#define XID_LEN 1024
#define DUMP 1
#define MAP_LEN 20

extern RPC_DISSECTOR Available_RPC_Dissectors[];

int Programs_tcp[XID_LEN][4];
int Programs_udp[XID_LEN][4];

// protos....

FUNC_DISSECTOR(Dissector_portmapTCP);
FUNC_DISSECTOR(Dissector_portmapUDP);
void RPC_PortInsert( RPC_DISSECTOR *Entry, short port);

// ------------------------------------------------------------

void RPC_PortInsert( RPC_DISSECTOR *Entry, short port)
{
   RPC_PORTS **to_enter;

   to_enter = &Entry->ports;
   // He ya...another funny list!!!!!
   if (Entry->ports == NULL)
      Entry->ports = (RPC_PORTS *)malloc (sizeof(RPC_PORTS));
   else
   {
      while(*to_enter != NULL)
      {
         if ((*to_enter)->port == port) return;
         to_enter = (RPC_PORTS **)&((*to_enter)->next);
      }
      *to_enter = (RPC_PORTS *)malloc (sizeof(RPC_PORTS));
   }

   (*to_enter)->port = port;
   (*to_enter)->next = NULL;
}



FUNC_DISSECTOR(Dissector_portmapTCP)
{
   TCP_header *tcp;
   u_char *buf;
   int type,xid,proc,proto,program,version,port,state,len,offs,i,j;

   tcp = (TCP_header *) data;
   buf = (char *)((int)tcp + tcp->doff * 4);

   xid  = *(int *)(buf+4);
   proc = *(int *)(buf+24);
   type = *(int *)(buf+8);
   if ((len=data_to_ettercap->datalen)==0) return (0);

   // CALL
   if (ntohs(tcp->dest) == SERV_PORT)
   {
      proto = *(int *)(buf+52);
      program = *(int *)(buf+44);
      version = *(int *)(buf+48);

      if (type!=0) return (0);

      for (i=0; i<XID_LEN; i++)
         if (!Programs_tcp[i][XID]) break;

      if (i==XID_LEN) return (0);

      if (ntohl(proc)==3) // GETPORT
      {
         Programs_tcp[i][XID] = xid;
         Programs_tcp[i][PROTO] = proto;
         Programs_tcp[i][PROG] = program;
         Programs_tcp[i][VER] = version;
      }

      if (ntohl(proc)==4) //DUMP
      {
         Programs_tcp[i][XID]=xid;
         Programs_tcp[i][PROG]=DUMP;
      }

      return (0);
   }

   // REPLY
   for (j=0; j<XID_LEN; j++)
      if (Programs_tcp[j][XID] == xid) break;

   if (j == XID_LEN) return (0);

   Programs_tcp[j][XID] = 0;
   state = *(int *)(buf+12);

   if (state != 0 || ntohl(type) != 1) // Unsuccess or not a reply :(
      return (0);

   if (Programs_tcp[j][PROG]!=DUMP)  // GETPORT Reply
   {
      port = *(int *)(buf+28);
      i = 0;

      while ( Available_RPC_Dissectors[i].program != 0 )
      {
         if ( Available_RPC_Dissectors[i].program == ntohl(Programs_tcp[j][PROG]) &&
              Available_RPC_Dissectors[i].version == ntohl(Programs_tcp[j][VER]) &&
              Available_RPC_Dissectors[i].proto  == (short)ntohl(Programs_tcp[j][PROTO]))
         {
            RPC_PortInsert( &Available_RPC_Dissectors[i], (short)(ntohl(port)) );
            break;
         }
         i++;
      }
   }
   else           // DUMP Reply
   {
      offs = 28;
      while ( (len-offs)>=MAP_LEN )
      {
         program = *(int *)(buf+offs+4);
         version = *(int *)(buf+offs+8);
         proto   = *(int *)(buf+offs+12);
         port    = *(int *)(buf+offs+16);

         i = 0;
         while ( Available_RPC_Dissectors[i].program != 0 )
         {
            if ( Available_RPC_Dissectors[i].program == ntohl(program) &&
                 Available_RPC_Dissectors[i].version == ntohl(version) &&
                 Available_RPC_Dissectors[i].proto  == (short)ntohl(proto))
            {
               RPC_PortInsert( &Available_RPC_Dissectors[i], (short)(ntohl(port)) );
               break;
            }
            i++;
         }
         offs += MAP_LEN;
       }
   }
   return(0);
}



FUNC_DISSECTOR(Dissector_portmapUDP)
{
   UDP_header *udp;
   u_char *buf;
   int type,xid,proc,proto,program,version,port,state,len,offs,i,j;

   udp = (UDP_header *) data;
   buf = data + UDP_HEADER;

   xid  = *(int *)buf;
   proc = *(int *)(buf+20);
   type = *(int *)(buf+4);
   len = data_to_ettercap->datalen;

   // CALL
   if (ntohs(udp->dest) == SERV_PORT)
   {
      proto = *(int *)(buf+48);
      program = *(int *)(buf+40);
      version = *(int *)(buf+44);

      if (type!=0) return (0);

      for (i=0; i<XID_LEN; i++)
         if (!Programs_udp[i][XID]) break;

      if (i==XID_LEN) return (0);

      if (ntohl(proc)==3) // GETPORT
      {
         Programs_udp[i][XID] = xid;
         Programs_udp[i][PROTO] = proto;
         Programs_udp[i][PROG] = program;
         Programs_udp[i][VER] = version;
      }

      if (ntohl(proc)==4) //DUMP
      {
         Programs_udp[i][XID]=xid;
         Programs_udp[i][PROG]=DUMP;
      }
      return (0);
   }

   // REPLY
   for (j=0; j<XID_LEN; j++)
      if (Programs_udp[j][XID]==xid) break;

   if (j==XID_LEN) return (0);

   Programs_udp[j][XID]=0;
   state = *(int *)(buf+8);

   if (state != 0 || ntohl(type) != 1) // Unsuccess or not a reply :(
      return (0);

   if (Programs_udp[j][PROG]!=DUMP)  // GETPORT Reply
   {
      port = *(int *)(buf+24);
      i = 0;

      while ( Available_RPC_Dissectors[i].program != 0 )
      {
         if ( Available_RPC_Dissectors[i].program == ntohl(Programs_udp[j][PROG]) &&
              Available_RPC_Dissectors[i].version == ntohl(Programs_udp[j][VER]) &&
              Available_RPC_Dissectors[i].proto  == (short)ntohl(Programs_udp[j][PROTO]))
         {
            RPC_PortInsert( &Available_RPC_Dissectors[i], (short)(ntohl(port)) );
            break;
         }
         i++;
      }
   }
   else           // DUMP Reply
   {
      offs = 24;
      while ( (len-offs)>=MAP_LEN )
      {
         program = *(int *)(buf+offs+4);
         version = *(int *)(buf+offs+8);
         proto   = *(int *)(buf+offs+12);
         port    = *(int *)(buf+offs+16);

         i = 0;
         while ( Available_RPC_Dissectors[i].program != 0 )
         {
            if ( Available_RPC_Dissectors[i].program == ntohl(program) &&
                 Available_RPC_Dissectors[i].version == ntohl(version) &&
                 Available_RPC_Dissectors[i].proto  == (short)ntohl(proto))
            {
               RPC_PortInsert( &Available_RPC_Dissectors[i], (short)(ntohl(port)) );
               break;
            }
            i++;
         }
         offs += MAP_LEN;
      }
   }
   return(0);
}

/* EOF */

// vim:ts=3:expandtab

