static uint32_t ExDNSDG(DNSDG * pDNSDG, int16_t cbMax) { bool fMachineOrder = DNSIsInMachineOrder(pDNSDG); uint8_t * pRR = pDNSDG->rrRecords; uint8_t * pEnd = ((uint8_t *) pDNSDG) + cbMax; uint16_t cQD = pDNSDG->dnsHdr.QDCOUNT; uint16_t cRR = pDNSDG->dnsHdr.ANCOUNT + pDNSDG->dnsHdr.NSCOUNT + pDNSDG->dnsHdr.ARCOUNT + cQD; uint16_t i = 0; // exchange the header // ExEndian(&pDNSDG->dnsHdr.ID, sizeof(pDNSDG->dnsHdr.ID)); ExEndian(&pDNSDG->dnsHdr.QDCOUNT, sizeof(pDNSDG->dnsHdr.QDCOUNT)); ExEndian(&pDNSDG->dnsHdr.ANCOUNT, sizeof(pDNSDG->dnsHdr.ANCOUNT)); ExEndian(&pDNSDG->dnsHdr.NSCOUNT, sizeof(pDNSDG->dnsHdr.NSCOUNT)); ExEndian(&pDNSDG->dnsHdr.ARCOUNT, sizeof(pDNSDG->dnsHdr.ARCOUNT)); DNSToggleOrder(pDNSDG); // if we got the counts wrong before, get them correct now. if(!fMachineOrder) { cQD = pDNSDG->dnsHdr.QDCOUNT; cRR = pDNSDG->dnsHdr.ANCOUNT + pDNSDG->dnsHdr.NSCOUNT + pDNSDG->dnsHdr.ARCOUNT + cQD; } // now switch all of the answer records for(i=0; i < cRR && pRR < pEnd; i++) { pRR = ExDNSRRecord(pRR, (i < cQD), pEnd); } return(pRR - ((uint8_t *) pDNSDG)); }
static uint8_t * ExDNSRRecord(uint8_t * pRR, bool fQuestionRecord, uint8_t * pEnd) { DNSRR * pDNSRR = NULL; uint8_t * pEx = DNSSkipName(pRR, pEnd); // skip past the name pDNSRR = (DNSRR *) pEx; pEx += (fQuestionRecord ? sizeof(DNSQRR) : sizeof(DNSRR)); // this is an error case if(pEx > pEnd) { return(NULL); } ExEndian(&pDNSRR->TYPE, sizeof(pDNSRR->TYPE)); ExEndian(&pDNSRR->CLASS, sizeof(pDNSRR->CLASS)); if(!fQuestionRecord) { ExEndian(&pDNSRR->TTL, sizeof(pDNSRR->TTL)); ExEndian(&pDNSRR->RDLENGTH, sizeof(pDNSRR->RDLENGTH)); pEx += pDNSRR->RDLENGTH; } // went too far if(pEx > pEnd) { return(NULL); } return(pEx); }
static void ExICMP0(void * pv, bool fStartsInMachineOrder) { // indentifier ExEndian(pv, sizeof(uint16_t)); pv += sizeof(uint16_t); // sequence ExEndian(pv, sizeof(uint16_t)); }
uint32_t ExICMP(void * pv, uint32_t cb, bool fStartsInMachineOrder) { ICMPHDR * pICMPHdr = pv; ICMPTYPE icmpType; uint32_t cbRet = 0; if(cb < sizeof(ICMPHDR)) return(0); if(fStartsInMachineOrder) { pICMPHdr->checksum = 0; icmpType = pICMPHdr->icmpType; ExEndian(&pICMPHdr->icmpType, sizeof(pICMPHdr->icmpType)); } else { // checksum should be 0, otherwise there is an error. pICMPHdr->checksum = CalculateChecksum(0, pv, cb); ExEndian(&pICMPHdr->icmpType, sizeof(pICMPHdr->icmpType)); icmpType = pICMPHdr->icmpType; } ExEndian(&pICMPHdr->code, sizeof(pICMPHdr->code)); switch(icmpType) { case icmpTypeEcho: case icmpTypeEchoReply: if(cb < sizeof(ICMPT0)) return(0); ExICMP0(pv + sizeof(ICMPHDR), fStartsInMachineOrder); cbRet = cb; // don't know the length of the data, must trust what came in. break; case icmpTypeDestinationUnreachable: case icmpTypeSourceQuench: case icmpTypeRedirect: case icmpTypeTimeExceeded: case icmpTypeParameterProblem: case icmpTypeTimestamp: case icmpTypeTimestampReply: case icmpTypeInformationRequest: case icmpTypeInformationReply: default: return(0); } if(fStartsInMachineOrder) { // already in proper order pICMPHdr->checksum = CalculateChecksum(0, pv, cbRet); } return(cbRet); }
uint32_t ExUDPHeader(IPSTACK * pIpStack, bool fStartsInMachineOrder) { uint16_t sum = ~(ippnUDP << 8); // checksum of the psuedo header if(ILIsIPv6(pIpStack->pLLAdp)) { sum = CalculateChecksum(sum, &pIpStack->pIPv6Hdr->ipSrc, sizeof(IPv6)); sum = CalculateChecksum(sum, &pIpStack->pIPv6Hdr->ipDest, sizeof(IPv6)); } else { sum = CalculateChecksum(sum, &pIpStack->pIPv4Hdr->ipSrc, sizeof(IPv4)); sum = CalculateChecksum(sum, &pIpStack->pIPv4Hdr->ipDest, sizeof(IPv4)); } // must put in network order, and do check sum if(fStartsInMachineOrder) { pIpStack->pUDPHdr->checksum = 0; // set this to zero for calcluation ExEndian(&pIpStack->pUDPHdr->portSrc, sizeof(pIpStack->pUDPHdr->portSrc)); ExEndian(&pIpStack->pUDPHdr->portDest, sizeof(pIpStack->pUDPHdr->portDest)); ExEndian(&pIpStack->pUDPHdr->cbHdrData, sizeof(pIpStack->pUDPHdr->cbHdrData)); sum = CalculateChecksum(sum, pIpStack->pUDPHdr, sizeof(UDPHDR)); // must do the size twice because we have this in the psuedo header as well sum = CalculateChecksum(sum, &pIpStack->pUDPHdr->cbHdrData, sizeof(pIpStack->pUDPHdr->cbHdrData)); } else { sum = CalculateChecksum(sum, pIpStack->pUDPHdr, sizeof(UDPHDR)); // must do the size twice because we have this in the psuedo header as well sum = CalculateChecksum(sum, &pIpStack->pUDPHdr->cbHdrData, sizeof(pIpStack->pUDPHdr->cbHdrData)); // switch order ExEndian(&pIpStack->pUDPHdr->portSrc, sizeof(pIpStack->pUDPHdr->portSrc)); ExEndian(&pIpStack->pUDPHdr->portDest, sizeof(pIpStack->pUDPHdr->portDest)); ExEndian(&pIpStack->pUDPHdr->cbHdrData, sizeof(pIpStack->pUDPHdr->cbHdrData)); } // add the data pIpStack->pUDPHdr->checksum = CalculateChecksum(sum, pIpStack->pPayload, pIpStack->cbPayload); // RFC 768, if zero and outgoing, make all FFs if(fStartsInMachineOrder) { if(pIpStack->pUDPHdr->checksum == 0) { pIpStack->pUDPHdr->checksum = 0xFFFF; } } else if(pIpStack->pUDPHdr->checksum != 0) { return(ipsIpStackChecksumError); } return(ipsSuccess); }
static bool ExTCPOptions(TCPHDR * pTCPHdr) { uint32_t cbOptions = pTCPHdr->dataOffset * sizeof(uint32_t) - sizeof(TCPHDR); TCPOPTION * pOptions = (TCPOPTION *) (pTCPHdr + 1); if(pTCPHdr->dataOffset == (sizeof(TCPHDR) / sizeof(uint32_t))) { return(true); } else if(pTCPHdr->dataOffset < (sizeof(TCPHDR) / sizeof(uint32_t))) { return(false); } // run the options while(cbOptions > 0) { // if this is switch(pOptions->optionKind) { case tcpOpKdEndOfList: return(true); break; case tcpOpKdNoOperation: cbOptions--; pOptions = (TCPOPTION *) (((void *) pOptions) + 1); // there is no length, so just go to the next option continue; break; default: break; } // check the size to if(pOptions->length > cbOptions) { return(false); } switch(pOptions->optionKind) { case tcpOpKdMaxSegSize: ExEndian(pOptions->rgu16, sizeof(uint16_t)); break; case tcpOpKdSAckMult: case tcpOpKdTimestamp: { uint32_t i = 0; uint32_t j = (pOptions->length-2) / sizeof(uint32_t); for(i=0; i<j; i++) { ExEndian(&pOptions->rgu16[2*i], sizeof(uint32_t)); } } break; case tcpOpKdWindowScale: case tcpOpKdSAck: case tcpOpKdAltChksumReq: case tcpOpKdAltChksumData: default: break; } // go to the next option cbOptions -= pOptions->length; pOptions = (TCPOPTION *) (((void *) pOptions) + pOptions->length); } return(true); }
uint32_t ExTCPHeader(IPSTACK * pIpStack, bool fStartsInMachineOrder) { uint16_t sum = ~(ippnTCP << 8); uint16_t cbT = pIpStack->cbTranportHeader + pIpStack->cbPayload; // checksum of the psuedo header // remember dataOffset is a byte, so we don't care if in machine or network order ExEndian(&cbT, sizeof(cbT)); sum = CalculateChecksum(sum, &cbT, sizeof(cbT)); if(ILIsIPv6(pIpStack->pLLAdp)) { sum = CalculateChecksum(sum, &pIpStack->pIPv6Hdr->ipSrc, sizeof(IPv6)); sum = CalculateChecksum(sum, &pIpStack->pIPv6Hdr->ipDest, sizeof(IPv6)); } else { sum = CalculateChecksum(sum, &pIpStack->pIPv4Hdr->ipSrc, sizeof(IPv4)); sum = CalculateChecksum(sum, &pIpStack->pIPv4Hdr->ipDest, sizeof(IPv4)); } // must put in network order, and do checksum if(fStartsInMachineOrder) { if(!ExTCPOptions(pIpStack->pTCPHdr)) { return(ipsIpStackParsingError); } pIpStack->pTCPHdr->checksum = 0; // set this to zero for calcluation ExEndian(&pIpStack->pTCPHdr->portSrc, sizeof(pIpStack->pTCPHdr->portSrc)); ExEndian(&pIpStack->pTCPHdr->portDest, sizeof(pIpStack->pTCPHdr->portDest)); ExEndian(&pIpStack->pTCPHdr->seqNbr, sizeof(pIpStack->pTCPHdr->seqNbr)); ExEndian(&pIpStack->pTCPHdr->ackNbr, sizeof(pIpStack->pTCPHdr->ackNbr)); ExEndian(&pIpStack->pTCPHdr->window, sizeof(pIpStack->pTCPHdr->window)); ExEndian(&pIpStack->pTCPHdr->urgentPtr, sizeof(pIpStack->pTCPHdr->urgentPtr)); sum = CalculateChecksum(sum, pIpStack->pTCPHdr, pIpStack->cbTranportHeader); } else { sum = CalculateChecksum(sum, pIpStack->pTCPHdr, pIpStack->cbTranportHeader); // switch order ExEndian(&pIpStack->pTCPHdr->portSrc, sizeof(pIpStack->pTCPHdr->portSrc)); ExEndian(&pIpStack->pTCPHdr->portDest, sizeof(pIpStack->pTCPHdr->portDest)); ExEndian(&pIpStack->pTCPHdr->seqNbr, sizeof(pIpStack->pTCPHdr->seqNbr)); ExEndian(&pIpStack->pTCPHdr->ackNbr, sizeof(pIpStack->pTCPHdr->ackNbr)); ExEndian(&pIpStack->pTCPHdr->window, sizeof(pIpStack->pTCPHdr->window)); ExEndian(&pIpStack->pTCPHdr->urgentPtr, sizeof(pIpStack->pTCPHdr->urgentPtr)); if(!ExTCPOptions(pIpStack->pTCPHdr)) { return(ipsIpStackParsingError); } } // add the data pIpStack->pTCPHdr->checksum = CalculateChecksum(sum, pIpStack->pPayload, pIpStack->cbPayload); // RFC 768, if zero and outgoing, make all FFs if(fStartsInMachineOrder) { if(pIpStack->pTCPHdr->checksum == 0) { pIpStack->pTCPHdr->checksum = 0xFFFF; } } else if(pIpStack->pTCPHdr->checksum != 0) { return(ipsIpStackChecksumError); } return(ipsSuccess); }
// this puts to order and fills in all of the stack pointers // payload must at least point to the frame // or it must already be parsed, it can just change order bool IPSParseToOrder(IPSTACK * pIpStack, uint32_t Order) { uint32_t state = ipsIpStackNotParsed; const bool fInMachineOrder = (pIpStack->headerOrder == MACHINE_ORDER); const bool fSwitchingOrder = (pIpStack->headerOrder != Order); bool fInMachineOrderT = fInMachineOrder; uint16_t cbT = 0; uint16_t etpnT = 0; // see if we are already done. if(pIpStack->fFrameIsParsed && !fSwitchingOrder) { return(true); } while(state != ipsSuccess) { switch(state) { // in the first state we must get the frame info case ipsIpStackNotParsed: fInMachineOrderT = fInMachineOrder; // if parsed, just get our size if(pIpStack->fFrameIsParsed) { cbT = pIpStack->cbFrame; } // if not parsed, what we are parsing is in the payload pointer else { pIpStack->pFrameII = (ETHERNETII_FRAME *) pIpStack->pPayload; cbT = pIpStack->cbPayload; } // if we are switching order if(fSwitchingOrder) { cbT = ExEthernetFrameHeader(pIpStack->pFrameII, cbT, fInMachineOrderT); fInMachineOrderT = !fInMachineOrder; } if(cbT < sizeof(ETHERNETII_FRAME)) { state = ipsIpStackParsingError; break; } pIpStack->etherType = pIpStack->pFrameII->etherType; if(!fInMachineOrderT) { ExEndian(&pIpStack->etherType, sizeof(ETHERTYPE)); } pIpStack->fIEEE802Frame = IsIEEE802(pIpStack->etherType); if(pIpStack->fIEEE802Frame) { if(cbT < sizeof(ETHERNET_802_FRAME)) { state = ipsIpStackParsingError; break; } pIpStack->etherType = pIpStack->pFrame802->snap.etherType; if(!fInMachineOrderT) { ExEndian(&pIpStack->etherType, sizeof(ETHERTYPE)); } pIpStack->cbFrame = sizeof(ETHERNET_802_FRAME); } else { pIpStack->cbFrame = sizeof(ETHERNETII_FRAME); } // update payload and state if(!pIpStack->fFrameIsParsed) { pIpStack->pPayload += pIpStack->cbFrame; pIpStack->cbPayload -= pIpStack->cbFrame; } // go to the next state state = pIpStack->etherType; break; case ethertypeIPv4: // if parsed, just get our size if(pIpStack->fFrameIsParsed) { cbT = pIpStack->cbIPHeader; } // if not parsed, what we are parsing is in the payload pointer else { pIpStack->pIPv4Hdr = (IPv4HDR *) pIpStack->pPayload; cbT = pIpStack->cbPayload; } if(cbT < sizeof(IPv4HDR)) { state = ipsIpStackParsingError; break; } // no Endian to worry on this one, it is only a byte long pIpStack->cbIPHeader = pIpStack->pIPv4Hdr->cdwHeader * sizeof(uint32_t); if(pIpStack->cbIPHeader > cbT) { state = ipsIpStackParsingError; break; } if(!pIpStack->fFrameIsParsed) { uint16_t cbTotal = pIpStack->pIPv4Hdr->cbTotal; pIpStack->protocol = pIpStack->pIPv4Hdr->protocol; if(!fInMachineOrder) { ExEndian(&cbTotal, sizeof(uint16_t)); } if(cbTotal > pIpStack->cbPayload) { state = ipsIpStackParsingError; break; } pIpStack->pPayload += pIpStack->cbIPHeader; // this is very important, we must truncate junk at the end of the payload // cbTotal MUST come from what is specified in the header, and cbPayload MUST // represent the value that cbTotal defines (less the IP header as that is part of cbTotal). // this MUST be an "=" calculation NOT a -= cbIPHeader! pIpStack->cbPayload = cbTotal - pIpStack->cbIPHeader; } if(fSwitchingOrder) { cbT = ExILIPv4Header(pIpStack->pIPv4Hdr, pIpStack->cbIPHeader, fInMachineOrder); // if we are coming from network order // and switching to machine order // and the checksum is not zero, we had a checksum error // that will be the only error that will cause cbT != sizeof(IPv4HDR) if(cbT != sizeof(IPv4HDR)) { state = ipsIpStackChecksumError; break; } } state = pIpStack->protocol; break; case ippnUDP: state = ipsSuccess; // parse out the UDP header if(!pIpStack->fFrameIsParsed) { pIpStack->pUDPHdr = (UDPHDR *) pIpStack->pPayload; pIpStack->cbTranportHeader = sizeof(UDPHDR); cbT = pIpStack->pUDPHdr->cbHdrData; if(!fInMachineOrder) { ExEndian(&cbT, sizeof(cbT)); } if(cbT < pIpStack->cbPayload) { state = ipsIpStackParsingError; break; } pIpStack->pPayload += sizeof(UDPHDR); pIpStack->cbPayload = cbT - sizeof(UDPHDR); } // put in proper order and calculate the checksum if(fSwitchingOrder) { state = ExUDPHeader(pIpStack, fInMachineOrder); } break; case ippnTCP: state = ipsSuccess; // parse out the TCP header if(!pIpStack->fFrameIsParsed) { pIpStack->pTCPHdr = (TCPHDR *) pIpStack->pPayload; pIpStack->cbTranportHeader = pIpStack->pTCPHdr->dataOffset * sizeof(uint32_t); if(pIpStack->cbTranportHeader > pIpStack->cbPayload) { state = ipsIpStackParsingError; break; } pIpStack->pPayload += pIpStack->cbTranportHeader; pIpStack->cbPayload -= pIpStack->cbTranportHeader; } // put in proper order and calculate the checksum if(fSwitchingOrder) { state = ExTCPHeader(pIpStack, fInMachineOrder); } break; case ippnICMP: if(fSwitchingOrder) { cbT = ExICMP(pIpStack->pPayload, pIpStack->cbPayload, fInMachineOrder); if(cbT != pIpStack->cbPayload) { state = ipsIpStackParsingError; break; } // see if we got a checksum error // because this is the payload, do not make it a hard error if(!fInMachineOrder && pIpStack->pICMPHdr->checksum != 0) { pIpStack->ipss = ipssChecksumError; } } state = ipsSuccess; break; case ethertypeARP: // unfortunately the adaptor may give me a bigger buffer than I think I need. if(pIpStack->cbPayload < sizeof(ARPIPv4)) { state = ipsIpStackParsingError; break; } etpnT = pIpStack->pARPIPv4->etherType; if(!fInMachineOrder) { ExEndian(&etpnT, sizeof(etpnT)); } if(etpnT != ethertypeIPv4) { state = ipsIpStackNotSupportedPkt; break; } // get the payload set to the correct size as the adaptor may give us too many bytes with junk at the end pIpStack->cbPayload = sizeof(ARPIPv4); cbT = sizeof(ARPIPv4); if(fSwitchingOrder) { cbT = ExARPDatagram(pIpStack->pARPIPv4, pIpStack->cbPayload, fInMachineOrder); } if(cbT == sizeof(ARPIPv4)) { state = ipsSuccess; } else { state = ipsIpStackParsingError; } break; case ipsIpStackChecksumError: pIpStack->ipss = ipssChecksumError; pIpStack->fFrameIsParsed = false; return(false); break; case ipsIpStackParsingError: pIpStack->ipss = ipssCorruptPkt; pIpStack->fFrameIsParsed = false; return(false); break; case ethertypeIPv6: // TODO case ipsIpStackNotSupportedPkt: default: pIpStack->ipss = ipssNotSupported; pIpStack->fFrameIsParsed = false; return(false); break; } } if(fSwitchingOrder) { pIpStack->headerOrder = ~pIpStack->headerOrder; } pIpStack->fFrameIsParsed = true; return(true); }