📄 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 + -