LCOV - code coverage report
Current view: top level - src - ICMP.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 55 191 28.8 %
Date: 2010-12-13 Functions: 10 21 47.6 %
Branches: 19 69 27.5 %

           Branch data     Line data    Source code
       1                 :            : // $Id: ICMP.cc 6219 2008-10-01 05:39:07Z vern $
       2                 :            : //
       3                 :            : // See the file "COPYING" in the main distribution directory for copyright.
       4                 :            : 
       5                 :            : #include "config.h"
       6                 :            : 
       7                 :            : #include "Net.h"
       8                 :            : #include "NetVar.h"
       9                 :            : #include "Event.h"
      10                 :            : #include "ICMP.h"
      11                 :            : 
      12                 :          5 : ICMP_Analyzer::ICMP_Analyzer(Connection* c)
      13                 :          5 : : TransportLayerAnalyzer(AnalyzerTag::ICMP, c)
      14                 :            :         {
      15                 :          5 :         icmp_conn_val = 0;
      16                 :          5 :         c->SetInactivityTimeout(icmp_inactivity_timeout);
      17                 :          5 :         request_len = reply_len = -1;
      18                 :          5 :         }
      19                 :            : 
      20                 :          0 : ICMP_Analyzer::ICMP_Analyzer(AnalyzerTag::Tag tag, Connection* c)
      21                 :          0 : : TransportLayerAnalyzer(tag, c)
      22                 :            :         {
      23                 :          0 :         icmp_conn_val = 0;
      24                 :          0 :         c->SetInactivityTimeout(icmp_inactivity_timeout);
      25                 :          0 :         request_len = reply_len = -1;
      26                 :          0 :         }
      27                 :            : 
      28                 :          5 : void ICMP_Analyzer::Done()
      29                 :            :         {
      30                 :          5 :         TransportLayerAnalyzer::Done();
      31                 :          5 :         Unref(icmp_conn_val);
      32                 :          5 :         matcher_state.FinishEndpointMatcher();
      33                 :          5 :         }
      34                 :            : 
      35                 :            : void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
      36                 :         31 :                         bool is_orig, int seq, const IP_Hdr* ip, int caplen)
      37                 :            :         {
      38         [ -  + ]:         31 :         assert(ip);
      39                 :            : 
      40                 :         31 :         TransportLayerAnalyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);
      41                 :            : 
      42                 :            :         // We need the min() here because Ethernet frame padding can lead to
      43                 :            :         // caplen > len.
      44         [ -  + ]:         31 :         if ( packet_contents )
      45                 :            :                 // Subtract off the common part of ICMP header.
      46                 :          0 :                 PacketContents(data + 8, min(len, caplen) - 8);
      47                 :            : 
      48                 :         31 :         const struct icmp* icmpp = (const struct icmp*) data;
      49                 :         31 :         len = arg_len;
      50                 :            : 
      51 [ +  - ][ +  - ]:         31 :         if ( ! ignore_checksums && caplen >= len &&
         [ -  + ][ -  + ]
      52                 :            :              icmp_checksum(icmpp, len) != 0xffff )
      53                 :            :                 {
      54                 :          0 :                 Weird("bad_ICMP_checksum");
      55                 :          0 :                 return;
      56                 :            :                 }
      57                 :            : 
      58                 :         31 :         Conn()->SetLastTime(current_timestamp);
      59                 :            : 
      60         [ -  + ]:         31 :         if ( rule_matcher )
      61                 :            :                 {
      62         [ #  # ]:          0 :                 if ( ! matcher_state.MatcherInitialized(is_orig) )
      63                 :          0 :                         matcher_state.InitEndpointMatcher(this, ip, len, is_orig, 0);
      64                 :            :                 }
      65                 :            : 
      66                 :         31 :         type = icmpp->icmp_type;
      67                 :         31 :         code = icmpp->icmp_code;
      68                 :            : 
      69                 :            :         // Move past common portion of ICMP header.
      70                 :         31 :         data += 8;
      71                 :         31 :         caplen -= 8;
      72                 :         31 :         len -= 8;
      73                 :            : 
      74         [ +  - ]:         31 :         int& len_stat = is_orig ? request_len : reply_len;
      75         [ +  + ]:         31 :         if ( len_stat < 0 )
      76                 :          5 :                 len_stat = len;
      77                 :            :         else
      78                 :         26 :                 len_stat += len;
      79                 :            : 
      80                 :         31 :         NextICMP(current_timestamp, icmpp, len, caplen, data);
      81                 :            : 
      82         [ -  + ]:         31 :         if ( rule_matcher )
      83                 :            :                 matcher_state.Match(Rule::PAYLOAD, data, len, is_orig,
      84                 :         31 :                                         false, false, true);
      85                 :            :         }
      86                 :            : 
      87                 :            : void ICMP_Analyzer::NextICMP(double /* t */, const struct icmp* /* icmpp */,
      88                 :            :                                 int /* len */, int /* caplen */,
      89                 :         31 :                                 const u_char*& /* data */)
      90                 :            :         {
      91                 :         31 :         ICMPEvent(icmp_sent);
      92                 :         31 :         }
      93                 :            : 
      94                 :         31 : void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f)
      95                 :            :         {
      96         [ -  + ]:         31 :         if ( ! f )
      97                 :         31 :                 return;
      98                 :            : 
      99                 :          0 :         val_list* vl = new val_list;
     100                 :          0 :         vl->append(BuildConnVal());
     101                 :          0 :         vl->append(BuildICMPVal());
     102                 :            : 
     103                 :          0 :         ConnectionEvent(f, vl);
     104                 :            :         }
     105                 :            : 
     106                 :          0 : RecordVal* ICMP_Analyzer::BuildICMPVal()
     107                 :            :         {
     108         [ #  # ]:          0 :         if ( ! icmp_conn_val )
     109                 :            :                 {
     110                 :          0 :                 icmp_conn_val = new RecordVal(icmp_conn);
     111                 :            : 
     112                 :          0 :                 icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr()));
     113                 :          0 :                 icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr()));
     114                 :          0 :                 icmp_conn_val->Assign(2, new Val(type, TYPE_COUNT));
     115                 :          0 :                 icmp_conn_val->Assign(3, new Val(code, TYPE_COUNT));
     116                 :          0 :                 icmp_conn_val->Assign(4, new Val(len, TYPE_COUNT));
     117                 :            :                 }
     118                 :            : 
     119                 :          0 :         Ref(icmp_conn_val);
     120                 :            : 
     121                 :          0 :         return icmp_conn_val;
     122                 :            :         }
     123                 :            : 
     124                 :          0 : RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
     125                 :            :         {
     126                 :          0 :         const struct ip* ip = (const struct ip *) data;
     127                 :          0 :         uint32 ip_hdr_len = ip->ip_hl * 4;
     128                 :            : 
     129                 :            :         uint32 ip_len, frag_offset;
     130                 :          0 :         TransportProto proto = TRANSPORT_UNKNOWN;
     131                 :            :         int DF, MF, bad_hdr_len, bad_checksum;
     132                 :            :         uint32 src_addr, dst_addr;
     133                 :            :         uint32 src_port, dst_port;
     134                 :            : 
     135 [ #  # ][ #  # ]:          0 :         if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) )
     136                 :            :                 { // We don't have an entire IP header.
     137                 :          0 :                 bad_hdr_len = 1;
     138                 :          0 :                 ip_len = frag_offset = 0;
     139                 :          0 :                 DF = MF = bad_checksum = 0;
     140                 :          0 :                 src_addr = dst_addr = 0;
     141                 :          0 :                 src_port = dst_port = 0;
     142                 :            :                 }
     143                 :            : 
     144                 :            :         else
     145                 :            :                 {
     146                 :          0 :                 bad_hdr_len = 0;
     147                 :          0 :                 ip_len = ntohs(ip->ip_len);
     148                 :          0 :                 bad_checksum = ones_complement_checksum((void*) ip, ip_hdr_len, 0) != 0xffff;
     149                 :            : 
     150                 :          0 :                 src_addr = uint32(ip->ip_src.s_addr);
     151                 :          0 :                 dst_addr = uint32(ip->ip_dst.s_addr);
     152                 :            : 
     153   [ #  #  #  # ]:          0 :                 switch ( ip->ip_p ) {
     154                 :          0 :                 case 1:         proto = TRANSPORT_ICMP; break;
     155                 :          0 :                 case 6:         proto = TRANSPORT_TCP; break;
     156                 :          0 :                 case 17:        proto = TRANSPORT_UDP; break;
     157                 :            : 
     158                 :            :                 // Default uses TRANSPORT_UNKNOWN, per initialization above.
     159                 :            :                 }
     160                 :            : 
     161                 :          0 :                 uint32 frag_field = ntohs(ip->ip_off);
     162                 :          0 :                 DF = frag_field & 0x4000;
     163                 :          0 :                 MF = frag_field & 0x2000;
     164                 :          0 :                 frag_offset = frag_field & /* IP_OFFMASK not portable */ 0x1fff;
     165                 :          0 :                 const u_char* transport_hdr = ((u_char *) ip + ip_hdr_len);
     166                 :            : 
     167         [ #  # ]:          0 :                 if ( uint32(len) < ip_hdr_len + 4 )
     168                 :            :                         {
     169                 :            :                         // 4 above is the magic number meaning that both
     170                 :            :                         // port numbers are included in the ICMP.
     171                 :          0 :                         bad_hdr_len = 1;
     172                 :          0 :                         src_port = dst_port = 0;
     173                 :            :                         }
     174                 :            : 
     175   [ #  #  #  # ]:          0 :                 switch ( proto ) {
     176                 :            :                 case TRANSPORT_ICMP:
     177                 :            :                         {
     178                 :            :                         const struct icmp* icmpp =
     179                 :          0 :                                 (const struct icmp *) transport_hdr;
     180                 :            :                         bool is_one_way;        // dummy
     181                 :          0 :                         src_port = ntohs(icmpp->icmp_type);
     182                 :          0 :                         dst_port = ntohs(ICMP_counterpart(icmpp->icmp_type,
     183                 :            :                                                         icmpp->icmp_code,
     184                 :            :                                                         is_one_way));
     185                 :            :                         }
     186                 :          0 :                         break;
     187                 :            : 
     188                 :            :                 case TRANSPORT_TCP:
     189                 :            :                         {
     190                 :            :                         const struct tcphdr* tp =
     191                 :          0 :                                 (const struct tcphdr *) transport_hdr;
     192                 :          0 :                         src_port = ntohs(tp->th_sport);
     193                 :          0 :                         dst_port = ntohs(tp->th_dport);
     194                 :            :                         }
     195                 :          0 :                         break;
     196                 :            : 
     197                 :            :                 case TRANSPORT_UDP:
     198                 :            :                         {
     199                 :            :                         const struct udphdr* up =
     200                 :          0 :                                 (const struct udphdr *) transport_hdr;
     201                 :          0 :                         src_port = ntohs(up->uh_sport);
     202                 :          0 :                         dst_port = ntohs(up->uh_dport);
     203                 :            :                         }
     204                 :          0 :                         break;
     205                 :            : 
     206                 :            :                 default:
     207                 :          0 :                         src_port = dst_port = ntohs(0);
     208                 :            :                 }
     209                 :            :                 }
     210                 :            : 
     211                 :          0 :         RecordVal* iprec = new RecordVal(icmp_context);
     212                 :          0 :         RecordVal* id_val = new RecordVal(conn_id);
     213                 :            : 
     214                 :          0 :         id_val->Assign(0, new AddrVal(src_addr));
     215                 :          0 :         id_val->Assign(1, new PortVal(src_port, proto));
     216                 :          0 :         id_val->Assign(2, new AddrVal(dst_addr));
     217                 :          0 :         id_val->Assign(3, new PortVal(dst_port, proto));
     218                 :          0 :         iprec->Assign(0, id_val);
     219                 :            : 
     220                 :          0 :         iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
     221                 :          0 :         iprec->Assign(2, new Val(proto, TYPE_COUNT));
     222                 :          0 :         iprec->Assign(3, new Val(frag_offset, TYPE_COUNT));
     223                 :          0 :         iprec->Assign(4, new Val(bad_hdr_len, TYPE_BOOL));
     224                 :          0 :         iprec->Assign(5, new Val(bad_checksum, TYPE_BOOL));
     225                 :          0 :         iprec->Assign(6, new Val(MF, TYPE_BOOL));
     226                 :          0 :         iprec->Assign(7, new Val(DF, TYPE_BOOL));
     227                 :            : 
     228                 :          0 :         return iprec;
     229                 :            :         }
     230                 :            : 
     231                 :         26 : bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */)
     232                 :            :         {
     233                 :         26 :         return 0;
     234                 :            :         }
     235                 :            : 
     236                 :          0 : void ICMP_Analyzer::Describe(ODesc* d) const
     237                 :            :         {
     238                 :          0 :         d->Add(Conn()->StartTime());
     239                 :          0 :         d->Add("(");
     240                 :          0 :         d->Add(Conn()->LastTime());
     241                 :          0 :         d->AddSP(")");
     242                 :            : 
     243                 :          0 :         d->Add(dotted_addr(Conn()->OrigAddr()));
     244                 :          0 :         d->Add(".");
     245                 :          0 :         d->Add(type);
     246                 :          0 :         d->Add(".");
     247                 :          0 :         d->Add(code);
     248                 :            : 
     249                 :          0 :         d->SP();
     250                 :          0 :         d->AddSP("->");
     251                 :            : 
     252                 :          0 :         d->Add(dotted_addr(Conn()->RespAddr()));
     253                 :          0 :         }
     254                 :            : 
     255                 :         20 : void ICMP_Analyzer::UpdateEndpointVal(RecordVal* endp, int is_orig)
     256                 :            :         {
     257                 :         20 :         Conn()->EnableStatusUpdateTimer();
     258                 :            : 
     259         [ +  + ]:         20 :         int size = is_orig ? request_len : reply_len;
     260         [ +  + ]:         20 :         if ( size < 0 )
     261                 :            :                 {
     262                 :         15 :                 endp->Assign(0, new Val(0, TYPE_COUNT));
     263                 :         15 :                 endp->Assign(1, new Val(int(ICMP_INACTIVE), TYPE_COUNT));
     264                 :            :                 }
     265                 :            : 
     266                 :            :         else
     267                 :            :                 {
     268                 :          5 :                 endp->Assign(0, new Val(size, TYPE_COUNT));
     269                 :          5 :                 endp->Assign(1, new Val(int(ICMP_ACTIVE), TYPE_COUNT));
     270                 :            :                 }
     271                 :         20 :         }
     272                 :            : 
     273                 :          0 : unsigned int ICMP_Analyzer::MemoryAllocation() const
     274                 :            :         {
     275                 :            :         return Analyzer::MemoryAllocation()
     276                 :            :                 + padded_sizeof(*this) - padded_sizeof(Connection)
     277         [ #  # ]:          0 :                 + (icmp_conn_val ? icmp_conn_val->MemoryAllocation() : 0);
     278                 :            :         }
     279                 :            : 
     280                 :          0 : ICMP_Echo_Analyzer::ICMP_Echo_Analyzer(Connection* c)
     281                 :          0 : : ICMP_Analyzer(AnalyzerTag::ICMP_Echo, c)
     282                 :            :         {
     283                 :          0 :         }
     284                 :            : 
     285                 :            : void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
     286                 :          0 :                                          int caplen, const u_char*& data)
     287                 :            :         {
     288         [ #  # ]:          0 :         EventHandlerPtr f = type == ICMP_ECHO ? icmp_echo_request : icmp_echo_reply;
     289         [ #  # ]:          0 :         if ( ! f )
     290                 :          0 :                 return;
     291                 :            : 
     292                 :          0 :         int iid = ntohs(icmpp->icmp_hun.ih_idseq.icd_id);
     293                 :          0 :         int iseq = ntohs(icmpp->icmp_hun.ih_idseq.icd_seq);
     294                 :            : 
     295                 :          0 :         BroString* payload = new BroString(data, caplen, 0);
     296                 :            : 
     297                 :          0 :         val_list* vl = new val_list;
     298                 :          0 :         vl->append(BuildConnVal());
     299                 :          0 :         vl->append(BuildICMPVal());
     300                 :          0 :         vl->append(new Val(iid, TYPE_COUNT));
     301                 :          0 :         vl->append(new Val(iseq, TYPE_COUNT));
     302                 :          0 :         vl->append(new StringVal(payload));
     303                 :            : 
     304                 :          0 :         ConnectionEvent(f, vl);
     305                 :            :         }
     306                 :            : 
     307                 :            : 
     308                 :            : void ICMP_Context_Analyzer::NextICMP(double t, const struct icmp* icmpp,
     309                 :          0 :                                 int len, int caplen, const u_char*& data)
     310                 :            :         {
     311                 :          0 :         EventHandlerPtr f = 0;
     312      [ #  #  # ]:          0 :         switch ( type ) {
     313                 :          0 :         case ICMP_UNREACH: f = icmp_unreachable; break;
     314                 :          0 :         case ICMP_TIMXCEED: f = icmp_time_exceeded; break;
     315                 :            :         }
     316                 :            : 
     317         [ #  # ]:          0 :         if ( f )
     318                 :            :                 {
     319                 :          0 :                 val_list* vl = new val_list;
     320                 :          0 :                 vl->append(BuildConnVal());
     321                 :          0 :                 vl->append(BuildICMPVal());
     322                 :          0 :                 vl->append(new Val(code, TYPE_COUNT));
     323                 :          0 :                 vl->append(ExtractICMPContext(caplen, data));
     324                 :            : 
     325                 :          0 :                 ConnectionEvent(f, vl);
     326                 :            :                 }
     327                 :          0 :         }
     328                 :            : 
     329                 :            : 
     330                 :         31 : int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
     331                 :            :         {
     332                 :         31 :         is_one_way = false;
     333                 :            : 
     334                 :            :         // return the counterpart type if one exists.  This allows us
     335                 :            :         // to track corresponding ICMP requests/replies.
     336                 :            :         // Note that for the two-way ICMP messages, icmp_code is
     337                 :            :         // always 0 (RFC 792).
     338 [ -  -  -  -  - :         31 :         switch ( icmp_type ) {
          -  -  -  -  + ]
     339                 :          0 :         case ICMP_ECHO:                 return ICMP_ECHOREPLY;
     340                 :          0 :         case ICMP_ECHOREPLY:            return ICMP_ECHO;
     341                 :          0 :         case ICMP_TSTAMP:               return ICMP_TSTAMPREPLY;
     342                 :          0 :         case ICMP_TSTAMPREPLY:          return ICMP_TSTAMP;
     343                 :          0 :         case ICMP_IREQ:                 return ICMP_IREQREPLY;
     344                 :          0 :         case ICMP_IREQREPLY:            return ICMP_IREQ;
     345                 :          0 :         case ICMP_ROUTERSOLICIT:        return ICMP_ROUTERADVERT;
     346                 :          0 :         case ICMP_MASKREQ:              return ICMP_MASKREPLY;
     347                 :          0 :         case ICMP_MASKREPLY:            return ICMP_MASKREQ;
     348                 :            : 
     349                 :         31 :         default:                        is_one_way = true; return icmp_code;
     350                 :            :         }
     351 [ +  - ][ +  - ]:          6 :         }

Generated by: LCOV version 1.8