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); }
// does not calculate checksum; this is calculated when we got to network order static bool IPSSetHeader(IPSTACK * pIpStack, IPSTATUS * pStatus) { if(ILIsIPv6(pIpStack->pLLAdp)) { memset(pIpStack->pIPv6Hdr, 0, sizeof(IPv6HDR)); AssignStatusSafely(pStatus, ipsIpStackNotSupportedPkt); return(false); } else { if(pIpStack->cbIPHeader < sizeof(IPv4HDR)) { AssignStatusSafely(pStatus, ipsInvalidIPv4HedearSize); return(false);; } // Per RFC 791 pIpStack->cbIPHeader = sizeof(IPv4HDR); pIpStack->pIPv4Hdr->version = 4; pIpStack->pIPv4Hdr->cdwHeader = sizeof(IPv4HDR) / 4; pIpStack->pIPv4Hdr->cbTotal = sizeof(IPv4HDR) + pIpStack->cbTranportHeader + pIpStack->cbPayload; pIpStack->pIPv4Hdr->ident = 0; pIpStack->pIPv4Hdr->u16 = 0; pIpStack->pIPv4Hdr->timeToLive = TIME_TO_LIVE; pIpStack->pIPv4Hdr->protocol = pIpStack->protocol; // typically ippnICMP, ippnTCP, ippnUDP pIpStack->pIPv4Hdr->hdrChecksum = 0; // for calculations, this is set to 0, RFC 791 pIpStack->pIPv4Hdr->ipSrc.u32 = pIpStack->pLLAdp->ipMy.ipv4.u32; pIpStack->pIPv4Hdr->ipDest.u32 = IPv4BROADCAST.u32; // TODO: Process options pIpStack->fOptionPresent = false; return(true); } AssignStatusSafely(pStatus, ipsIpStackParsingError); return(false); }
// only called for incoming packets void TCPProcess(IPSTACK * pIpStack) { TCPSOCKET * pSocketCur = NULL; TCPSOCKET * pSocketListen = NULL; TCPSOCKET * pSocketExact = NULL; // see if this is directed to my IP if( !( // this is not my IP address // my IPv4 address (!ILIsIPv6(pIpStack->pLLAdp) && pIpStack->pLLAdp->ipMy.ipv4.u32 == pIpStack->pIPv4Hdr->ipDest.u32) || // my IPv6 addresss (memcmp(&pIpStack->pLLAdp->ipMy.ipv6, &pIpStack->pIPv6Hdr->ipDest, sizeof(IPv6)) == 0) )) { // just get out if it is not for me return; } // look at all of the sockets while((pSocketCur = (TCPSOCKET*)FFNext(&g_ffptActiveTCPSockets, pSocketCur)) != NULL) { if( pSocketCur->tcpState > tcpListen && pIpStack->pTCPHdr->portPair == pSocketCur->s.portPair && // matches the remote IP ((!ILIsIPv6(pIpStack->pLLAdp) && pSocketCur->s.ipRemote.ipv4.u32 == pIpStack->pIPv4Hdr->ipSrc.u32) || (memcmp(&pSocketCur->s.ipRemote.ipv6, &pIpStack->pIPv4Hdr->ipSrc, sizeof(IPv6)) == 0)) ) { pSocketExact = pSocketCur; break; } else if(pSocketCur->tcpState == tcpListen && pSocketCur->s.portLocal == pIpStack->pTCPHdr->portDest && pIpStack->pTCPHdr->fSyn) { pSocketListen = pSocketCur; } } // see if we did not find an exact match // but we are listening if(pSocketExact == NULL) { pSocketExact = pSocketListen; } // a match to an active socket if(pSocketExact != NULL) { IPSUpdateARPEntry(pIpStack); memcpy(&pSocketExact->s.macRemote, &pIpStack->pFrameII->macSrc, sizeof(MACADDR)); TCPStateMachine(pIpStack, pSocketExact, NULL); } // to no socket at all, this will cause a RST to be sent. else { TCPStateMachine(pIpStack, NULL, NULL); } }
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); }
bool DNSInit(const LLADP * pLLAdp, void * rgbDNSMem, uint32_t cbDNSMem, HPMGR hPMGR, IPSTATUS * pStatus) { IPSTATUS status = ipsSuccess; DNSMEM * pDNSMem = (DNSMEM *) rgbDNSMem; uint32_t i = 0; if(pLLAdp == NULL) { status = ipsAdaptorMustBeSpecified; } else if(hPMGR == NULL) { status = ipsNoPMGRGiven; } else if(rgbDNSMem == NULL) { status = ipsDNSMemIsNULL; } else if(cbDNSMem < sizeof(DNSMEM)) { status = ipsDNSNotEnoughMem; } else if(pLLAdp->pDNSMem != NULL) { status = ipsDNSAlreadyInitialized; } else if(ILIsIPv6(pLLAdp)) { status = ipsIPv6NotSupported; } if(IsIPStatusAnError(status)) { AssignStatusSafely(pStatus, status); return(false); } memset(pDNSMem, 0, cbDNSMem); if(&pDNSMem->socket != UDPOpenWithSocket(pLLAdp, &pDNSMem->socket, hPMGR, &IPv4BROADCAST, portDNSServer, portDynamicallyAssign, &status) || IsIPStatusAnError(status)) { UDPClose(&pDNSMem->socket); AssignStatusSafely(pStatus, status); return(false); } pDNSMem->dnsNSMax = (cbDNSMem - sizeof(DNSMEM)) / sizeof(IPv4or6); pDNSMem->cDhcpNS = 0; pDNSMem->iDNSCur = DNSiInvalid; pDNSMem->iDNSWorks = DNSiInvalid; pDNSMem->dnsState = dnsReady; pDNSMem->cTry = 0; ((LLADP *) pLLAdp)->pDNSMem = pDNSMem; // initialize them all to the Google NS // that way there is something in all of the slots // this will get over written if DHCP is used. for(i=0; i<pDNSMem->dnsNSMax; i++) { if((i % 2) == 0) { pDNSMem->dnsNS[i].ipv4.u32 = 0x04040808; // Google public DNS server } else { pDNSMem->dnsNS[i].ipv4.u32 = 0x08080808; // Google public DNS server } } AssignStatusSafely(pStatus, status); return(true); }
// Notes on dnsNSMax and cDhcpNS. You would think that we should only cycle through cDhcpNS as this is the number // DNS servers given to us by DHCP, however, sometimes DHCP does not give us good DNS servers and for the // SNTP server to work, we need a good DNS server. So we continue to check the default, pre initialized google DNS // servers after the DHCP DNS servers are checked first. If we get a lot of DNS servers from DHCP, then ultimately // all of the pre installed google servers will be overwritten in the dnsNSMax list, but if we got a lot of DNS servers // the assumption is that they are good ones. In particular, I found that Verizon did not give me very good DNS servers, they // could not resolve the SNTP time servers. static void DNSStateMachine(const LLADP * pLLAdp) { IPSTATUS status = ipsSuccess; if(pLLAdp == NULL || pLLAdp->pDNSMem == NULL || !ILIsIPSetup(pLLAdp, NULL)) { return; } switch(pLLAdp->pDNSMem->dnsState) { case dnsSend: if(pLLAdp->pDNSMem->dnsNSMax == 0) { pLLAdp->pDNSMem->dnsState = dnsReady; pLLAdp->pDNSMem->cTry = 0; break; } else if(pLLAdp->pDNSMem->cTry >= (pLLAdp->pDNSMem->dnsNSMax * DNSMINTRY)) { if(pLLAdp->pDNSMem->iDNSCur == pLLAdp->pDNSMem->iDNSWorks) { pLLAdp->pDNSMem->iDNSWorks = DNSiInvalid; } pLLAdp->pDNSMem->iDNSCur = DNSiInvalid; pLLAdp->pDNSMem->dnsState = dnsReady; pLLAdp->pDNSMem->cTry = 0; break; } else if(pLLAdp->pDNSMem->iDNSWorks < pLLAdp->pDNSMem->dnsNSMax) { pLLAdp->pDNSMem->iDNSCur = pLLAdp->pDNSMem->iDNSWorks; } else if(pLLAdp->pDNSMem->iDNSCur >= pLLAdp->pDNSMem->dnsNSMax) { pLLAdp->pDNSMem->iDNSCur = 0; } else { pLLAdp->pDNSMem->iDNSCur = (pLLAdp->pDNSMem->iDNSCur + 1) % pLLAdp->pDNSMem->dnsNSMax; } // set this up for an attempt to get the IP address memcpy(&pLLAdp->pDNSMem->socket.s.ipRemote, &pLLAdp->pDNSMem->dnsNS[pLLAdp->pDNSMem->iDNSCur], ILIPSize(pLLAdp)); // fall thru on success case dnsReadySend: // clear the current IP address memset(&pLLAdp->pDNSMem->ip, 0, sizeof(IPv4or6)); // just make this unique for this pass pLLAdp->pDNSMem->dnsDG.dnsHdr.ID++; // set my timers and counts pLLAdp->pDNSMem->cTry++; pLLAdp->pDNSMem->tTimeout = dnsWaitForRetry; pLLAdp->pDNSMem->tStart = SYSGetMilliSecond(); // send out the DNS datagram UDPSend(&pLLAdp->pDNSMem->socket, (uint8_t *) &pLLAdp->pDNSMem->dnsDG, pLLAdp->pDNSMem->cbDNSDG, &status); // see if it went out. if(IsIPStatusAnError(status)) { pLLAdp->pDNSMem->dnsState = dnsReady; pLLAdp->pDNSMem->cTry = 0; } else { pLLAdp->pDNSMem->dnsState = dnsWaiting; } break; case dnsWaiting: { uint16_t cbDG = UDPAvailable(&pLLAdp->pDNSMem->socket) ; IPSTATUS status; if(cbDG > sizeof(DNSHDR)) { // we need some space for the datagram uint8_t rgbDNSDG[DNSMAXUDPSIZE]; DNSDG * pDNSDG = (DNSDG *) rgbDNSDG; uint8_t * pEnd = NULL; uint8_t * pCName = NULL; DNSRR * pDNSRRA = NULL; // read the DNS datagram cbDG = UDPRead(&pLLAdp->pDNSMem->socket, rgbDNSDG, DNSMAXUDPSIZE, &status); // There are some servers setting this and they should not! RFC 6195 2.1 and I need to ignore it // Plus this is used internally to determine if we are in machine or network order. This is in network order right now. pDNSDG->dnsHdr.Z = 0; // now put in machine order. cbDG = ExDNSDG(pDNSDG, cbDG); pEnd = rgbDNSDG + cbDG; // if this is not a my response, keep waiting // remember the ID is not exchanged, so network and machine order will have the same ID if(!pDNSDG->dnsHdr.QR || pDNSDG->dnsHdr.ID != pLLAdp->pDNSMem->dnsDG.dnsHdr.ID) { break; } // ops and error occured, jump to finish with error // go to the error state with no address found if(pDNSDG->dnsHdr.RCODE != DNSRCODENoError) { // this is a failure case; go to the next DNS server pLLAdp->pDNSMem->dnsState = dnsSend; break; } // get the canonical name for what we are looking for // the first record is the question which has the name we used. // we need to use the one in this datagram because we do memory range // checking and if we use the QR we sent, it would be out of the memory range pCName = DNSFindCName(pDNSDG, DNSRRAN, pDNSDG->rrRecords, pEnd); // now find the A record pDNSRRA = DNSFindRR(pDNSDG, NULL, DNSRRAN, DNSTYPEA, DNSCLASSIN, pCName, pEnd); // if we got the A record we are done if( pDNSRRA != NULL && ((ILIsIPv6(pLLAdp) && pDNSRRA->RDLENGTH == sizeof(IPv6)) || (!ILIsIPv6(pLLAdp) && pDNSRRA->RDLENGTH == sizeof(IPv4)) ) ) { // copy in our result memcpy(&pLLAdp->pDNSMem->ip, pDNSRRA->RDATA, pDNSRRA->RDLENGTH); // say we are done pLLAdp->pDNSMem->dnsState = dnsReady; pLLAdp->pDNSMem->cTry = 0; // We got an IP so we know this DNS server can work, remember that if(pLLAdp->pDNSMem->iDNSCur < pLLAdp->pDNSMem->dnsNSMax) { pLLAdp->pDNSMem->iDNSWorks = pLLAdp->pDNSMem->iDNSCur; } // get out we found it and are done. break; } // by default we will go to the next well know sever unless we pick up a better NS to go to pLLAdp->pDNSMem->dnsState = dnsSend; // we did not find anything, so update our DNS request to use the new CName if(pCName != pDNSDG->rrRecords) { // make the new DNS packet with the CName instead of what we were using uint16_t cbMax = DNSCreateIPv4QueryDN(pLLAdp, rgbDNSDG, pCName, pEnd, &pLLAdp->pDNSMem->dnsDG); pLLAdp->pDNSMem->cbDNSDG = ExDNSDG(&pLLAdp->pDNSMem->dnsDG, cbMax); } // Didn't find an A record // But maybe there is a name server we should try. // If we asked for recursion and go it, no sense working the issue ourselves. // likewise if there are now NS with IP addresses, no sense working the issue if(!(pDNSDG->dnsHdr.RD && pDNSDG->dnsHdr.RA) && pDNSDG->dnsHdr.NSCOUNT > 0 && pDNSDG->dnsHdr.ARCOUNT > 0) { // this DNS server gave us something, so remember it if(pLLAdp->pDNSMem->iDNSCur < pLLAdp->pDNSMem->dnsNSMax) { pLLAdp->pDNSMem->iDNSWorks = pLLAdp->pDNSMem->iDNSCur; } pDNSRRA = DNSFindNSARR(pDNSDG, pCName, pEnd, DNSTYPEA); // if this looks like a good IP address to try, lets contact that name server if(pDNSRRA != NULL && pDNSRRA->RDLENGTH == sizeof(IPv4)) { // say were are not using one of our well known DNS servers pLLAdp->pDNSMem->iDNSCur = DNSiInvalid; // Put the IP in our socket memcpy(&pLLAdp->pDNSMem->socket.s.ipRemote, pDNSRRA->RDATA, pDNSRRA->RDLENGTH); pLLAdp->pDNSMem->dnsState = dnsReadySend; } } else if(pLLAdp->pDNSMem->iDNSWorks == pLLAdp->pDNSMem->iDNSCur) { pLLAdp->pDNSMem->iDNSWorks = DNSiInvalid; } } else if((SYSGetMilliSecond() - pLLAdp->pDNSMem->tStart) >= pLLAdp->pDNSMem->tTimeout) { pLLAdp->pDNSMem->dnsState = dnsWaitTry; } } break; case dnsWaitTry: if(pLLAdp->pDNSMem->iDNSWorks == pLLAdp->pDNSMem->iDNSCur) { pLLAdp->pDNSMem->iDNSWorks = DNSiInvalid; } if((pLLAdp->pDNSMem->cTry % DNSMINTRY) == 0) { pLLAdp->pDNSMem->dnsState = dnsSend; } else { pLLAdp->pDNSMem->dnsState = dnsReadySend; } break; case dnsReady: pLLAdp->pDNSMem->cTry = 0; break; // noting to do here, either we have something in the DNS memory IP or not. case dnsRedirect: case dnsUninit: default: break; } }
// This is not a URL, this must be a domain nume such as www.foo.bar.com with an optional . at the end. bool DNSResolve(const LLADP * pLLAdp, uint8_t const * const pchDomainName, uint32_t cchDomanName, void * pIPvX, IPSTATUS * pStatus) { IPSTATUS status = ipsSuccess; // see if we are initialized if(pLLAdp == NULL) { status = ipsAdaptorMustBeSpecified; } else if( !ILIsIPSetup(pLLAdp, &status) ) { // do nothing, I got the status } else if(pLLAdp->pDNSMem == NULL || pLLAdp->pDNSMem->dnsState == dnsUninit) { status = ipsDNSIsNotInitialized; } else if(pchDomainName == NULL) { status = ipsDomainNameIsNULL; } else if(pIPvX == NULL) { status = ipsIPIsNULL; } // we are currently processing a DNS reqeust else if(pLLAdp->pDNSMem->dnsState != dnsReady) { // this is not the one we are working on! if(pLLAdp->pDNSMem->pchDomainName != pchDomainName) { status = ipsDNSIsInUse; } // this is the one we are working on, check to see if it is done. else { // go into the state machine. status = ipsDNSIsResolving; } } // we are done, see if we got it or not else if(pLLAdp->pDNSMem->pchDomainName == pchDomainName && pLLAdp->pDNSMem->cchDomainName == cchDomanName && strncmp((char *) pLLAdp->pDNSMem->pchDomainName, (char *) pchDomainName, cchDomanName) == 0) { if(ILIsIPv6(pLLAdp)) { // have no idea if(memcmp(&pLLAdp->pDNSMem->ip.ipv6, &IPv6NONE, sizeof(IPv6)) == 0) { status = ipsDNSFailedToResolve; } // got it else { memcpy(pIPvX, &pLLAdp->pDNSMem->ip.ipv6, sizeof(IPv6)); } } // IPv4 else { // have no idea if(pLLAdp->pDNSMem->ip.ipv4.u32 == IPv4NONE.u32) { status = ipsDNSFailedToResolve; } // got it else { memcpy(pIPvX, &pLLAdp->pDNSMem->ip.ipv4, sizeof(IPv4)); } } } // if we are ready, but he is asking for something else, start a new request. // check to see if the domain name starts with a number; as in IP address // TODO: IPv6 support else if(isdigit(*pchDomainName)) { uint32_t i = 0; uint32_t j = 0; uint32_t k = 0; uint8_t const * pch = pchDomainName; if(ILIsIPv6(pLLAdp)) { // TODO: do IPv6 support } else { for(i=0; i<4; i++) { for(j=0, k=0; j<3 && isdigit(*pch); j++, pch++) { k *= 10; k += (*pch - '0'); } if((i<3 && *pch == '.') || (i == 3 && (*pch == '/' || *pch == '\0'))) { ((IPv4 *) pIPvX)->u8[i] = (uint8_t) k; pch++; } // if is clearly not an IP address // try it as a domain name else { DNSStartIPv4Request(pLLAdp, pchDomainName, cchDomanName, &status); break; } } if(status == ipsSuccess) { // pretend we got the IP pLLAdp->pDNSMem->ip.ipv4.u32 = ((IPv4 *) pIPvX)->u32; pLLAdp->pDNSMem->pchDomainName = pchDomainName; pLLAdp->pDNSMem->cchDomainName = cchDomanName; } else { memcpy(pIPvX, &IPv4NONE, sizeof(IPv4)); } } } // otherwise we need to go look it up. else { DNSStartIPv4Request(pLLAdp, pchDomainName, cchDomanName, &status); } AssignStatusSafely(pStatus, status); return(status == ipsSuccess); }
IPSTACK * IPSInitIpStack(const LLADP * pLLAdp, void * pIpStackBuff, uint32_t type) { IPSTACK * pIpStack = (IPSTACK *) pIpStackBuff; // nothing open if(pIpStackBuff == NULL) { return(NULL); } // take this one // build it up to a default IPSTACK with pointers set in // we are clearing more than the IPSTACK, we are clearing all of the // following space for the headers. memset(pIpStackBuff, 0, IPStackEntrySize); pIpStack->fFreeIpStackToAdp = true; pIpStack->headerOrder = MACHINE_ORDER; pIpStack->pLLAdp = pLLAdp; pIpStack->pFrameII = (ETHERNETII_FRAME*)(((void *) pIpStack) + sizeof(IPSTACK)); pIpStack->cbFrame = sizeof(ETHERNETII_FRAME); pIpStack->pIPHeader = (((void *) pIpStack->pFrameII) + sizeof(ETHERNETII_FRAME)); if(ILIsIPv6(pLLAdp)) { pIpStack->etherType = ethertypeIPv6; pIpStack->cbIPHeader = sizeof(IPv6HDR); pIpStack->pTransportHeader = (pIpStack->pIPHeader + sizeof(IPv6HDR)); } else { pIpStack->etherType = ethertypeIPv4; pIpStack->cbIPHeader = sizeof(IPv4HDR); pIpStack->pTransportHeader = (pIpStack->pIPHeader + sizeof(IPv4HDR)); } switch(type) { case ippnICMP: pIpStack->pTransportHeader = NULL; pIpStack->cbTranportHeader = 0; pIpStack->protocol = ippnICMP; break; case ippnTCP: pIpStack->cbTranportHeader = sizeof(TCPHDR); pIpStack->protocol = ippnTCP; break; case ippnUDP: pIpStack->cbTranportHeader = sizeof(UDPHDR); pIpStack->protocol = ippnUDP; break; case ethertypeARP: pIpStack->pTransportHeader = NULL; pIpStack->cbTranportHeader = 0; pIpStack->pIPHeader = NULL; pIpStack->cbIPHeader = 0; pIpStack->etherType = ethertypeARP; break; default: return(NULL); } // put some defaults in // from here in, the IPSTACK values could be wrong, but we are putting something in. pIpStack->pPayload = NULL; pIpStack->cbPayload = 0; // build up the stack and headers with defaults // broadcast MAC and IP // protocol assumes TCP, but that can be changed later. // this should be an assert, it should never fail as this is // built from scratch and there should be no errors if(!IPSConstructIpStackHeaders(pIpStack, NULL)) { return(NULL); } return(pIpStack); }
void UDPProcess(IPSTACK * pIpStack) { UDPSOCKET * pSocketCur = NULL; UDPSOCKET * pSocketListen = NULL; UDPSOCKET * pSocketAnyRemoteIP = NULL; UDPSOCKET * pSocketExact = NULL; bool fBroadcast = false; bool fMyIP = ILIsIPv6(pIpStack->pLLAdp) ? ILIsMyIP(pIpStack->pLLAdp, &pIpStack->pIPv6Hdr->ipDest, &fBroadcast) : ILIsMyIP(pIpStack->pLLAdp, &pIpStack->pIPv4Hdr->ipDest, &fBroadcast); // see if this is directed to my IP if( !fMyIP ) { return; } // look at all listening sockets to see if the ports and remote IP match while((pSocketCur = FFNext(&g_ffptListeningUDPSockets, pSocketCur)) != NULL) { // make sure we have consistant IPs if(ILIsIPv6(pSocketCur->s.pLLAdp) == ILIsIPv6(pIpStack->pLLAdp)) { // listening socket, only check local port, remote port/IP will be set if( pSocketCur->s.portRemote == portListen && pSocketCur->s.portLocal == pIpStack->pUDPHdr->portDest ) { pSocketListen = pSocketCur; } // all connected sockets else if(pIpStack->pUDPHdr->portPair == pSocketCur->s.portPair) { // this is an IPv4 address if(!ILIsIPv6(pIpStack->pLLAdp)) { // exact match if(pSocketCur->s.ipRemote.ipv4.u32 == pIpStack->pIPv4Hdr->ipSrc.u32) { pSocketExact = pSocketCur; break; } // this is only supported for DHCP IPv4 else if(pSocketCur->s.ipRemote.ipv4.u32 == UDPAnyRemoteIPv4.u32) { pSocketAnyRemoteIP = pSocketCur; } } // else an IPv6 address else { // exact match if(memcmp(&pSocketCur->s.ipRemote.ipv6, &pIpStack->pIPv6Hdr->ipSrc, sizeof(IPv6)) == 0) { pSocketExact = pSocketCur; break; } } } } } // a match to an active socket if(pSocketExact == NULL) { if(pSocketAnyRemoteIP != NULL) { pSocketExact = pSocketAnyRemoteIP; } else if(pSocketListen != NULL) { pSocketExact = pSocketListen; pSocketExact->s.portRemote = pIpStack->pUDPHdr->portSrc; if(ILIsIPv6(pSocketExact->s.pLLAdp)) { memcpy(&pSocketExact->s.ipRemote.ipv6, &pIpStack->pIPv6Hdr->ipSrc, sizeof(IPv6)); } else { pSocketExact->s.ipRemote.ipv4.u32 = pIpStack->pIPv4Hdr->ipSrc.u32; } } } // no match to anything, get out. if(pSocketExact == NULL) { return; } // update our ARP table IPSUpdateARPEntry(pIpStack); memcpy(&pSocketExact->s.macRemote, &pIpStack->pFrameII->macSrc, sizeof(MACADDR)); // Receive the UDP input data UDPProcessRx(pIpStack, pSocketExact); }
bool UDPRawSend(const LLADP * pLLAdp, IPSTACK * pIpStack, const void * pIPvXDest, uint16_t portDest, uint16_t portSrc, const uint8_t * pDatagram, uint32_t cbDatagram, bool fFreeDatagramImmediately, IPSTATUS * pStatus) { bool fRet = false; IPSTATUS status = ipsSuccess; if(pLLAdp == NULL) { status = ipsAdaptorMustBeSpecified; } else if(pIpStack == NULL) { status = ipsIpStackNULL; } else if(pIPvXDest == NULL) { status = ipsIPAddressIsNull; } else if(pDatagram == NULL) { status = ipsUDPNullDatagram; } // sometimes we want to keep the actual buffer we passed in the IpStack // because we will later want to reuse it and don't want it copied and freed // the downside is, we have to know that the send is complete somehow; typically // would do this if you don't reuse the buffer until we get a response from the // remote and thus know we must have sent the datagram already. // this is typically NOT the way we would use this, but DHCP Does this extensively else if(!fFreeDatagramImmediately) { pIpStack->pPayload = (void *) pDatagram; } else if(IPSGetPayloadFromAdaptor(pIpStack, cbDatagram) == cbDatagram) { // this is ugly to have to copy the data but somewhat required // the problem is, when we send we may need to wait while an APR is proformed and that // will require that the pDatagram be constant, however on return from this funciton // the application may immediately reuse the memory to construct the next datagram memcpy(pIpStack->pPayload, pDatagram, cbDatagram); } else { status = ispOutOfMemory; } if(IsIPStatusAnError(status)) { AssignStatusSafely(pStatus, status); return(false); } pIpStack->pUDPHdr->portSrc = portSrc; pIpStack->pUDPHdr->portDest = portDest; pIpStack->pUDPHdr->cbHdrData += cbDatagram; pIpStack->cbPayload = cbDatagram; if(ILIsIPv6(pLLAdp)) { pIpStack->pIPv6Hdr->cbPayload = pIpStack->cbPayload; memcpy(&pIpStack->pIPv6Hdr->ipDest, pIPvXDest, sizeof(IPv6)); } else { pIpStack->pIPv4Hdr->cbTotal += pIpStack->cbPayload; memcpy(&pIpStack->pIPv4Hdr->ipDest, pIPvXDest, sizeof(IPv4)); } fRet = ILSend(pIpStack, pStatus); return(fRet); }