📄 nat_fragment.c
字号:
{ if (pEntry->flag & ENTRY_IN_USE) { if (pEntry->orgSrcAddr == pIpPacket->header.source_address && pEntry->orgDstAddr == pIpPacket->header.destination_address && pEntry->fragId == pIpPacket->header.identifier && pEntry->proto == pIpPacket->header.protocol) break; /* found one */ } pEntry = (NAT_FRAGMENT_ENTRY *)DLL_NEXT(&pEntry->u.node); } return pEntry; }/******************************************************************************* natFragAddrTranslate - Perform the fragment address translation** This routine first finds the translated address from the translation entry,* and then applies this new address to either the fragment's source address or* destination address depending on which port the fragment comes in. This * routine also takes consideration of the scenario described in RFC3022, * section 6.3. If that scenario occurs, the fragments other than for the first* connection will be dropped. This routine finally checks whether this * fragment is last one. If so, the translation entry allocated for this* fragmented datagram is freed.** RETURNS: PASS or FAIL **/enum TEST natFragAddrTranslate ( int portType, /* Global or local port type */ IP_PACKET * pIpPacket /* the fragment packet */ ) { int inx; NAT_FRAGMENT_ENTRY * pCacheEntry; NAT_FRAGMENT_ENTRY * pSearchEntry; IP_ADDRESS orgAddress; IP_ADDRESS *pAddrToChange = NULL; int portInx; portInx = portType == NAT_GLOBAL_PORT? GLOBAL_PORT_INX: LOCAL_PORTS_INX; inx = pIpPacket->header.identifier & FRAG_ID_HASH_MASK; pCacheEntry = &pFragResrcDesc[portInx]->pArray[inx]; pSearchEntry = pCacheEntry; if ((pSearchEntry = fragTranIdMatch(pCacheEntry, pIpPacket)) == NULL) { /* if coming from local ports, possibly the collision packets */ DBG_PRINT(("No translation, Packets from port %d dropped\n",portInx)); return FAIL; } if (portType == NAT_GLOBAL_PORT) { pAddrToChange = &pIpPacket->header.destination_address; DBG_PRINT(("Global Tran: inx=0x%x, srcAdr=0x%x, dstAdr=0x%x, id=0x%x\n", inx,(int)pSearchEntry->orgSrcAddr, (int)pSearchEntry->orgDstAddr, (int)pSearchEntry->fragId)); } else /* local ports */ { pAddrToChange = &pIpPacket->header.source_address; DBG_PRINT(("Local Tran: inx=0x%x,srcAdr=0x%x,dstAdr=0x%x,id=0x%x\n", inx,(int)pSearchEntry->orgSrcAddr,(int)pSearchEntry->orgDstAddr, pSearchEntry->fragId)); } /* This flag is set by default. The IP header checksum will be calculated * by the ip_output routine if this flag is set. Therefore no need to do * the IP header checksum fixup here if the condition is true. */ if (_ipCfgFlags & IP_DO_CHECKSUM_SND) *pAddrToChange = pSearchEntry->newAddr; else { orgAddress = *pAddrToChange; *pAddrToChange = pSearchEntry->newAddr; checksum_fixup ((BYTE *) &pIpPacket->header.header_checksum, (BYTE *) &orgAddress, sizeof (IP_ADDRESS), (BYTE *) pAddrToChange, sizeof (IP_ADDRESS)); } /* now check whether it is the last fragment */ if (!(pIpPacket->header.fragment & IP_FRAGMENT_FLAG_MORE_FRAGMENTS)) { /* last fragment, free the entry */ if (pSearchEntry == pCacheEntry) { DBG_PRINT(("Last fragment, cache entry freed\n")); pSearchEntry->flag = ENTRY_FREE; } else { DBG_PRINT(("Last fragment, list entry removed\n")); /* Not the cache entry, simply remove it from the list */ dllRemove(&pCacheEntry->u.list, &pSearchEntry->u.node); /* put back the freed entry to the free list */ dllAdd(&pFragResrcDesc[portInx]->fragFreeList, &pSearchEntry->u.node); } if (pFragResrcDesc[portInx]->outstandingEntries) pFragResrcDesc[portInx]->outstandingEntries--; } return PASS; } /******************************************************************************** natFragTranAddrSave - Save the translated address** This routine is called to save the result of the translated address derived* by the NAT address translation engine on the first fragment of the datagram.* The result is saved to the corresponding fragment translation entry. * This routine also check whether the collision problem described by RFC3022, * section 6.3 exist. If so this fragment will be dropped.** RETURNS: PASS or FAIL**/enum TEST natFragTranAddrSave ( int portType, /* global port or local ports */ void * pEntry, /* this fragment's translation entry */ IP_ADDRESS newAddr /* The translated address */ ) { NAT_FRAGMENT_ENTRY * pCacheEntry = NULL; NAT_FRAGMENT_ENTRY * pSearchEntry = NULL; NAT_FRAGMENT_ENTRY * pCurEntry; /* this fragment's translation entry */ int inx; pCurEntry = (NAT_FRAGMENT_ENTRY *)pEntry; /* save the translated address */ pCurEntry->newAddr = newAddr; DBG_PRINT(("portType: %s, translated address: 0x%x\n", portType == NAT_GLOBAL_PORT? "GLOBAL_PORT": "LOCAL_PORT", (int)newAddr)); if (portType == NAT_GLOBAL_PORT) return PASS; /* done */ else /* local ports */ { inx = pCurEntry->fragId & FRAG_ID_HASH_MASK; pCacheEntry = &pFragResrcDesc[LOCAL_PORTS_INX]->pArray[inx]; pSearchEntry = pCacheEntry; /* if the packet coming from the local port, there exists a collision * problem described by RFC3022, section 6.3. * We'll keep the first session alive and drop the second one. * A further step may be to defer sending the second datagram after * the first one is done. This requires to queue up all the fragments * related to this datagram and add to the netTask after the first one * is done. Don't know if worth the effort */ /* check if a collision entry exists */ while (pSearchEntry) { if (pSearchEntry != pCurEntry) { if (pSearchEntry->orgDstAddr == pCurEntry->orgDstAddr && pSearchEntry->fragId == pCurEntry->fragId && pSearchEntry->proto == pCurEntry->proto && pSearchEntry->newAddr == newAddr) break; /* found one */ } pSearchEntry =(NAT_FRAGMENT_ENTRY *)DLL_NEXT(&pSearchEntry->u.node); } if (pSearchEntry != NULL) { /* Fragments translated by this entry is in collistion*/ DBG_PRINT(("collision entry\n")); /* remove the translation entry */ if (pCurEntry == pCacheEntry) pCurEntry->flag = ENTRY_FREE; else { /* remove from the list and add it back to free list */ dllRemove(&pCacheEntry->u.list, &pCurEntry->u.node); dllAdd(&pFragResrcDesc[LOCAL_PORTS_INX]->fragFreeList, &pCurEntry->u.node); } if (pFragResrcDesc[LOCAL_PORTS_INX]->outstandingEntries) pFragResrcDesc[LOCAL_PORTS_INX]->outstandingEntries--; return FAIL; /* drop the current fragment */ } return PASS; } }/******************************************************************************** natFragTranTimerProcess - Process the fragment translation timer events.** This routine checks if the translation entry has timed out at the 1 second* (default) interval. The timeout value is set same as the TTL value in the IP* header. Normally the translation entry is deleted when the last fragment is* processed. In the case the last fragment never comes, this routine will do* the job.** The actual work is done in the netTask context just as the main NAT * translation engine does to prevent the race condition.** RETURNS: NONE*/void natFragTranTimerProcess (void) { int portInx; /* check if there is outstanding translation entries, if so, fire the * timer event function to start countdown */ for (portInx = 0; portInx < 2; portInx++) { if (pFragResrcDesc[portInx]->outstandingEntries) netJobAdd((FUNCPTR)fragTranTimerNetJob,portInx,0,0,0,0); } }/****************************************************************************** fragTranTimerNetJob - Fragment translation timer net job.** This function performs the actual work of processing the fragment * translation timer events in the netTask context.* */LOCAL void fragTranTimerNetJob ( int portInx ) { int inx; int count; for (inx = 0; inx < FRAG_CACHE_ARRAY_LEN; inx++) { count = entryTimerEventProcess(&pFragResrcDesc[portInx]->pArray[inx], &pFragResrcDesc[portInx]->fragFreeList); if (count) { if (pFragResrcDesc[portInx]->outstandingEntries >= count) pFragResrcDesc[portInx]->outstandingEntries -= count; else pFragResrcDesc[portInx]->outstandingEntries = 0; } } }/******************************************************************************* entryTimerEventProcess - Process the fragment translation entry's timeout.** RETURNS: number of the translation entries removed*/LOCAL int entryTimerEventProcess ( NAT_FRAGMENT_ENTRY * pCacheEntry, /* the cache entry */ DL_LIST * pFreeList /* the list to put back the free entries */ ) { NAT_FRAGMENT_ENTRY * pEntry; NAT_FRAGMENT_ENTRY * pNextEntry; int retCount = 0; pEntry = pCacheEntry; while (pEntry) { pNextEntry = (NAT_FRAGMENT_ENTRY *)DLL_NEXT(&pEntry->u.node); /* decrement the 1 second timer counter */ if (pEntry->flag & ENTRY_IN_USE) { if (pEntry->ttl) pEntry->ttl--; if (pEntry->ttl == 0) { /* this entry timed out */ if (pCacheEntry == pEntry) { /* this is the cache entry, mark it unused */ pEntry->flag = ENTRY_FREE; } else { /* list entry, remove it */ dllRemove(&pCacheEntry->u.list, &pEntry->u.node); /* put back the freed entry to the free list */ dllAdd(pFreeList, &pEntry->u.node); } retCount++; } } pEntry =pNextEntry; } return retCount; }#ifdef FRAGMENT_DEBUG/******************************************************************************* natFragShow - Display the usage of the translation entries ** This routine is for debug purpose**/void natFragShow (void) { NAT_FRAGMENT_ENTRY * pEntry; NAT_FRAGMENT_ENTRY * pCacheEntry; int portNum; int inx; int cacheEntryCnt; int listEntryCnt; int listFreeCnt; DL_NODE * pNode; listFreeCnt = 0; listEntryCnt = 0; cacheEntryCnt = 0; for (portNum = 0; portNum < 2; portNum++) { for (inx = 0; inx < FRAG_CACHE_ARRAY_LEN; inx++) { pCacheEntry = &pFragResrcDesc[portNum]->pArray[inx]; pEntry = pCacheEntry; if (pEntry->flag & ENTRY_IN_USE) cacheEntryCnt++; pEntry = (NAT_FRAGMENT_ENTRY *)DLL_NEXT(&pEntry->u.node); while (pEntry) { listEntryCnt++; pEntry = (NAT_FRAGMENT_ENTRY *)DLL_NEXT(&pEntry->u.node); } } } for (portNum = 0; portNum < 2; portNum++) { pNode = DLL_FIRST(&pFragResrcDesc[portNum]->fragFreeList); while (pNode) { listFreeCnt++; pNode = DLL_NEXT(pNode); } } printf("Use Cache Entries: 0x%x,Use list Entries: 0x%x,Free Entry: 0x%x\n", cacheEntryCnt,listEntryCnt,listFreeCnt); }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -