/* * Copyright (c) 2000-2004 QoSient, LLC * All rights reserved. * * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifndef ArgusICMP #define ArgusICMP #endif #include #include #include #include #include int ArgusCreateICMPFlow (struct ip *ip) { int retn = 0; unsigned int *icmphdr = (unsigned int *) ArgusThisUpHdr; struct icmp *icmp = (struct icmp *) icmphdr; struct ArgusICMPFlow *icmpFlow = &ArgusThisFlow->icmp_flow; ArgusThisDir = 0; icmpFlow->ip_src = ip->ip_src.s_addr; icmpFlow->ip_dst = ip->ip_dst.s_addr; icmpFlow->ip_p = ip->ip_p; if (STRUCTCAPTURED(*icmphdr)) { icmpFlow->type = icmp->icmp_type; icmpFlow->code = icmp->icmp_code; if (ICMP_INFOTYPE(icmp->icmp_type)) { switch (icmp->icmp_type) { case ICMP_ECHOREPLY: ArgusThisDir = 1; case ICMP_ECHO: icmpFlow->type = ICMP_ECHO; icmpFlow->id = ntohs(icmp->icmp_id); icmpFlow->ip_id = ntohs(icmp->icmp_seq); break; case ICMP_TSTAMPREPLY: ArgusThisDir = 1; case ICMP_TSTAMP: icmpFlow->type = ICMP_TSTAMP; break; case ICMP_IREQREPLY: ArgusThisDir = 1; case ICMP_IREQ: icmpFlow->type = ICMP_IREQ; break; case ICMP_MASKREPLY: ArgusThisDir = 1; case ICMP_MASKREQ: icmpFlow->type = ICMP_MASKREQ; break; } retn = 1; } else { struct ip *oip; struct udphdr *ouh; int hlen; oip = &icmp->icmp_ip; hlen = oip->ip_hl << 2; ouh = (struct udphdr *) (((u_char *) oip) + hlen); switch (icmp->icmp_type) { case ICMP_UNREACH: if (STRUCTCAPTURED(*icmp)) { switch (icmp->icmp_code) { case ICMP_UNREACH_PROTOCOL: icmpFlow->id = (unsigned short) icmp->icmp_ip.ip_p; break; case ICMP_UNREACH_PORT: icmpFlow->tp_p = oip->ip_p; icmpFlow->id = ntohs((unsigned short) ouh->uh_dport); break; case ICMP_UNREACH_NET: case ICMP_UNREACH_HOST: bcopy ((char *) &icmp->icmp_ip.ip_dst.s_addr, (char *)&icmpFlow->id, sizeof (int)); break; } retn = 1; } break; case ICMP_REDIRECT: if (STRUCTCAPTURED(*icmp)) { switch (icmp->icmp_code) { case ICMP_REDIRECT_TOSNET: case ICMP_REDIRECT_TOSHOST: icmpFlow->tp_p = oip->ip_tos; case ICMP_REDIRECT_NET: case ICMP_REDIRECT_HOST: bcopy ((char *) &icmp->icmp_ip.ip_dst.s_addr, (char *)&icmpFlow->id, sizeof (int)); break; } retn = 1; } break; default: retn = 1; break; } } if (ArgusThisDir) { unsigned int addr = icmpFlow->ip_src; icmpFlow->ip_src = icmpFlow->ip_dst; icmpFlow->ip_dst = addr; } } #ifdef ARGUSDEBUG ArgusDebug (8, "ArgusCreateICMPFlow(0x%x) returning %d\n", ip, retn); #endif return (retn); } #include #include void ArgusUpdateICMPState (struct ArgusFlowStruct *flowstr, unsigned char *state) { struct ip *ArgusTempIpHdr = ArgusThisIpHdr; unsigned char *ArgusTempSnapEnd = ArgusThisSnapEnd; struct icmp *icmp = (struct icmp *) ArgusThisUpHdr; struct ArgusICMPObject *icmpObj = NULL; ArgusUpdateAppState(flowstr, state); if (*state == ARGUS_START) { ArgusTallyTime (flowstr, *state); ArgusTallyStats (flowstr, *state); if ((icmpObj = (void *) ArgusCalloc (1, sizeof(struct ArgusICMPObject))) == NULL) { ArgusLog (LOG_ERR, "ArgusUpdateICMPState: ArgusCalloc %s", strerror(errno)); } else { if (flowstr->NetworkDSRBuffer != NULL) ArgusFree (flowstr->NetworkDSRBuffer); flowstr->NetworkDSRBuffer = icmpObj; icmpObj->type = ARGUS_ICMP_DSR; icmpObj->length = sizeof(*icmpObj); icmpObj->icmp_type = icmp->icmp_type; icmpObj->icmp_code = icmp->icmp_code; icmpObj->iseq = ntohs(icmp->icmp_seq); icmpObj->osrcaddr = ArgusThisIpHdr->ip_src.s_addr; icmpObj->odstaddr = ArgusThisIpHdr->ip_dst.s_addr; if (ICMP_INFOTYPE(icmp->icmp_type)) { switch (icmp->icmp_type) { case ICMP_ECHO: case ICMP_IREQ: case ICMP_MASKREQ: case ICMP_TSTAMP: icmpObj->status = ARGUS_REQUEST; break; case ICMP_MASKREPLY: icmp->icmp_mask = ntohl(icmp->icmp_mask); icmpObj->isrcaddr = icmp->icmp_mask; case ICMP_ECHOREPLY: case ICMP_IREQREPLY: case ICMP_TSTAMPREPLY: icmpObj->status = ARGUS_REPLY; break; } } else { struct ip oipbuf, *oip = &icmp->icmp_ip; if ((long) oip & (sizeof (long) - 1)) { bcopy ((char *)oip, (char *)&oipbuf, sizeof(struct ip)); oip = &oipbuf; } icmpObj->isrcaddr = ntohl(oip->ip_src.s_addr); icmpObj->idstaddr = ntohl(oip->ip_dst.s_addr); icmpObj->igwaddr = ntohl(icmp->icmp_gwaddr.s_addr); } } } else { flowstr->ArgusTimeout = ARGUS_IPTIMEOUT; if (((icmpObj = flowstr->NetworkDSRBuffer) != NULL) && (icmpObj->type == ARGUS_ICMP_DSR)) { if (ICMP_INFOTYPE(icmp->icmp_type)) { if ((flowstr->state.src.count == 0) && (flowstr->state.dst.count == 0)) icmpObj->icmp_type = icmp->icmp_type; switch (icmp->icmp_type) { case ICMP_ECHO: case ICMP_IREQ: case ICMP_TSTAMP: case ICMP_MASKREQ: if (ArgusResponseStatus && (icmpObj->status == ARGUS_REQUEST)) { ArgusSendFlowRecord (flowstr, ARGUS_STATUS); } *state = ARGUS_START; icmpObj->icmp_type = icmp->icmp_type; ArgusTallyTime (flowstr, *state); ArgusTallyStats (flowstr, *state); icmpObj->status = ARGUS_REQUEST; break; case ICMP_ECHOREPLY: case ICMP_IREQREPLY: case ICMP_TSTAMPREPLY: case ICMP_MASKREPLY: ArgusInProtocol = 1; ArgusTallyTime (flowstr, *state); ArgusTallyStats (flowstr, *state); flowstr->state.status |= ARGUS_CONNECTED; if (ArgusResponseStatus && (icmpObj->status == ARGUS_REQUEST)) ArgusSendFlowRecord (flowstr, ARGUS_STATUS); icmpObj->status = ARGUS_REPLY; break; default: ArgusTallyTime (flowstr, *state); ArgusTallyStats (flowstr, *state); if (flowstr->state.src.count && flowstr->state.dst.count) flowstr->state.status |= ARGUS_CONNECTED; else flowstr->state.status &= ~ARGUS_CONNECTED; break; } } else { ArgusTallyTime (flowstr, *state); ArgusTallyStats (flowstr, *state); } } else icmpObj = NULL; } if (!(ICMP_INFOTYPE(icmp->icmp_type))) { struct ArgusFlowStruct *flow = NULL; struct ArgusFlowStats *ArgusThisStats = NULL; struct ip *oip = &icmp->icmp_ip; int hlen = oip->ip_hl << 2; ArgusThisIpHdr = NULL; ArgusThisSnapEnd = ((unsigned char *)oip) + (hlen + 4); ArgusCreateIPFlow(oip); if (ArgusThisIpHdr) { ArgusThisUpHdr = (unsigned char *) ArgusThisIpHdr; ArgusThisSnapEnd = (unsigned char *) ArgusThisIpHdr; if ((flow = ArgusFindFlow()) != NULL) { if (flow->state.rev == ArgusThisDir) ArgusThisStats = &flow->state.src; else ArgusThisStats = &flow->state.dst; if (icmpObj && ((ArgusThisStats->ip_id == ArgusThisIpHdr->ip_id) || (ArgusThisStats->ip_id == htons(ArgusThisIpHdr->ip_id)))) { /* who sends ip_id messed up? */ if (flow->ICMPDSRBuffer == NULL) if ((flow->ICMPDSRBuffer = (void *) ArgusCalloc (1, sizeof(struct ArgusICMPObject))) == NULL) ArgusLog (LOG_ERR, "ArgusUpdateICMPState: ArgusCalloc %s", strerror(errno)); bcopy (icmpObj, flow->ICMPDSRBuffer, sizeof(*icmpObj)); switch (icmp->icmp_type) { case ICMP_UNREACH: flow->state.status |= ARGUS_ICMPUNREACH_MAPPED; break; case ICMP_REDIRECT: flow->state.status |= ARGUS_ICMPREDIREC_MAPPED; break; case ICMP_TIMXCEED: flow->state.status |= ARGUS_ICMPTIMXCED_MAPPED; break; } flow->state.lasttime = ArgusGlobalTime; if (ArgusResponseStatus && ((flow->state.src.count + flow->state.dst.count) == 1)) ArgusSendFlowRecord(flow, ARGUS_STOP); } } } ArgusThisIpHdr = ArgusTempIpHdr; ArgusThisSnapEnd = ArgusTempSnapEnd; } #ifdef ARGUSDEBUG ArgusDebug (8, "ArgusUpdateICMPState(0x%x, %d) returning\n", flowstr, state); #endif } #include void ArgusICMPFlowRecord (struct ArgusFlowStruct *flow, struct ArgusRecord *argus, unsigned char state) { int length = 0; struct ArgusICMPObject *icmpObj = (struct ArgusICMPObject *) flow->NetworkDSRBuffer; if (icmpObj && ((length = argus->ahdr.length) > 0)) { bcopy ((char *)icmpObj, &((char *)argus)[argus->ahdr.length], sizeof(*icmpObj)); argus->ahdr.length += sizeof(*icmpObj); } #ifdef ARGUSDEBUG ArgusDebug (5, "ArgusICMPFlowRecord(0x%x, 0x%x, %d) returning\n", flow, argus, state); #endif } void ArgusICMPMappedFlowRecord (struct ArgusFlowStruct *flow, struct ArgusRecord *argus, unsigned char state) { int length = 0; struct ArgusICMPObject *icmpObj = (struct ArgusICMPObject *) flow->ICMPDSRBuffer; if (icmpObj && ((length = argus->ahdr.length) > 0)) { bcopy ((char *)icmpObj, &((char *)argus)[argus->ahdr.length], sizeof(*icmpObj)); argus->ahdr.length += sizeof(*icmpObj); } #ifdef ARGUSDEBUG ArgusDebug (5, "ArgusICMPMappedFlowRecord(0x%x, 0x%x, %d) returning\n", flow, argus, state); #endif }