⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nat_fragment.c

📁 VXWORKS NAT 部分源代码2 有兴趣朋友可以参考下
💻 C
📖 第 1 页 / 共 2 页
字号:
/* nat_fragment.c */

/* Copyright 2000-2003 Wind River Systems, Inc. */

/* @format.tab-size 4, @format.use-tabs true, @format.new-line lf */

/*
modification history
--------------------
01e,18jul03,vks  changes for Virtual Stack
01d,16jun03,myz  rewrite this fragment translation module.
01c,23apr03,zhu  updated copyright
01b,26sep02,vvv  modified to add new fragment_info at start of fragment_list
01a,24sep02,vvv  replaced rw_container references with direct linked list
		 access for improved performance; added semaphore 
		 protection (SPR #79675)
*/

#include "stdio.h"
#include "nat.h"
#include "dllLib.h"
#include "netLib.h"

/*
DESCRIPTION

This library handles the fragments passing through the NAT device.
The reason the fragments need to be treated differently is because that only
the first fragment of the datagram carries the transport level protocol header
such as the UDP header, the subsequent fragments simply carry an IP header. 
Therefore there is simply not enough information for the NAT to perform the 
address translation in the NAPT mode when fragments come in from the global 
port side. 

The algorithm used by this library can be described as follows:
A translation entry(type of NAT_FRAGMENT_ENTRY) will be created when the first 
fragment comes in. The fields in the IP header which uniquely identifies the
subsequent fragments for the same datagram are saved in the entry. Then the
first fragment will continue to pass through the NAT address translation engine
just as the non-fragmented packet does. The translated address will be saved
to the entry. The subsequent fragments will not go through the NAT address 
translation engine, rather search the translation entries to find one with the
same datagram identifier and applies the translated address in the entry to
the proper address field. On the last fragment, the translation entry will be
freed. To make this process as efficient as possible, the program uses a 
combination of the cache and list objects for the translation entry operation. 
The cache consists of an array of the translation entries at the fixed location.
Simply a flag is used to indicate whether it is free or not. The array index 
is taken from the last least significant bits of the fragment identifier in 
the IP header. The cache entry is always used first for the fragment 
translation. In case another translation entry is needed with the same index, 
then the program will get one from a free entry list and put it to a list 
associated with the cache entry.  We expect most operation is done in the cache
entries. 

RFC3022 section 6.3. states:
"Translation of outbound TCP/UDP fragments(i.e., those originating from private
hosts) in NAPT setup are doomed to fail. The reason is as follows. Only the
first fragment contains the TCP/UDP header that would be necessary to associate
the packet to a session for translation purposes. Subsequent fragments do not
contain TCP/UDP port information, but simply carry the same fragmentation 
identifier specified in the first fragment. Say, two private hosts originated
fragmented TCP/UDP packets to the same destination host. And, they happened to 
use the same fragmentation identifier. When the target host receives the two
unrelated datagrams, carrying same fragmentation id, and from the same assigned
host address, it is unable to determine which of the two sessions the datagrams
belong to. Consequently, both sessions will be corrupted."

This library will check whether this scenario occurs. If it does, it 
will drop the fragments other then for the first session. Therefore instead
of corrupting both sessions, this handling will keep the first one alive.

*/


/* #define FRAGMENT_DEBUG */

#ifdef FRAGMENT_DEBUG

int fragDebug = 1;
#define DBG_PRINT(X) \
    do { \
    if (fragDebug) \
        printf X; \
    }while(0)
#else

#define DBG_PRINT(X)

#endif

#ifdef VIRTUAL_STACK
#include "netinet/vsLib.h"
#include "netinet/vsIp.h"
#endif /* VIRTUAL_STACK */

/* local defines */

/* This parameter should be adjusted based on the number of the outstanding
 * fragmented datagrams going through the NAT device at the same time.  
 * For example, in case there is always one or no fragmented traffic, 
 * the parameter FRAG_CACHE_ARRAY_LEN can be set to 1.
 */ 

#define FRAG_CACHE_ARRAY_LEN    (1 << 5)  /* 2**5, must be in the order of 2 */
#define FRAG_ID_HASH_MASK       (FRAG_CACHE_ARRAY_LEN - 1)
#define FRAG_PREALLOC_ENTRY_NUM  32       

/* fragment translation entry's flag value */

#define ENTRY_FREE               0x0    /* free to use */
#define ENTRY_IN_USE             0x1    /* being used */

/* index for global port, or ALL local ports*/
 
#define GLOBAL_PORT_INX    0
#define LOCAL_PORTS_INX    1

/* typedefs */

/* Fragment translation entry */

typedef struct 
    {
    union {
        DL_NODE node;     /* node as list element */
	DL_LIST list;     /* list header in cache entry */
	} u;
    ULONG   orgSrcAddr;   /* original fragment source address */
    ULONG   orgDstAddr;   /* original fragment destination address */
    UINT16  fragId;       /* fragment identifier in IP header */
    UINT8   proto;        /* protocol type in IP header */
    UINT8   ttl;          /* time to live for this entry same as in IP header */
    ULONG   newAddr;      /* the translated address */
    UINT32  flag;         /* entry's usage flag */
    } NAT_FRAGMENT_ENTRY; 

/* Memory resource node, used to keep track allocated memory */

typedef struct 
    {
    DL_NODE node;
    void *  pMem;   
    } NAT_FRAG_MEM_RESOURCE;

/* Fragment translation resource holder */ 

typedef struct 
    {
    DL_LIST fragFreeList;   /* The free translation entry list */
    DL_LIST memList;        /* The list to keep track of the allocated memory*/ 
    NAT_FRAGMENT_ENTRY * pArray;  /* the cache translation entry array */
    UINT32 outstandingEntries;    /* number of outstanding translation entries*/
    } NAT_FRAGMENT_RESOURCE_DESC;

/* One entry for Global port, one for ALL local ports */

LOCAL NAT_FRAGMENT_RESOURCE_DESC fragResrcDesc[2];
LOCAL NAT_FRAGMENT_RESOURCE_DESC * 
    pFragResrcDesc[2] = {&fragResrcDesc[0],&fragResrcDesc[1]};

/* function prototypes */

LOCAL BOOL entryTimerEventProcess (NAT_FRAGMENT_ENTRY *, DL_LIST *);
LOCAL void fragTranTimerNetJob (int);

/* externals */

#ifndef VIRTUAL_STACK
extern int _ipCfgFlags;
#endif /* VIRTUAL_STACK */

/****************************************************************************
*
* fragMemGet - Allocate a chunk of memory and keep the pointer in a list 
*
* RETURNS: the allocated memory or NULL
*/

LOCAL void * fragMemGet
    (
    int portInx,  /* global or local index */
    int size      /* size of requested memory */
    )
    {
    NAT_FRAG_MEM_RESOURCE * pResource;

    /* add overhead for remembering the allocated resource */

    size += sizeof(NAT_FRAG_MEM_RESOURCE);  

    if ((pResource = (NAT_FRAG_MEM_RESOURCE *)malloc(size)) == NULL)
        {
        nat_printf(NAT_PRINTF_ERROR,
                       "unable to allocate fragment list memory\n");
        return NULL;
        }

    /* zero out the memory */

    bzero((char *)pResource,size);

    /* remember the allocated memory*/

    pResource->pMem = (void *)pResource;

    dllAdd(&pFragResrcDesc[portInx]->memList,&pResource->node);

    return((void *)(pResource + 1));
    }

/*****************************************************************************
*
* fragFreeTranEntryAdd - Add pre-allocated translation entries to a free list
*
* This routine creates a batch of free translation entries and add them to the
* list.
*
*/

LOCAL STATUS fragFreeTranEntryAdd
    (
    int portInx,     /* global or local index */
    int numOfEntries /* number of translation entries to be added to the list*/
    )
    {
    NAT_FRAGMENT_ENTRY * pEntry;
    int size;
    int j;

    size = sizeof(NAT_FRAGMENT_ENTRY) * numOfEntries;

    if ((pEntry = (NAT_FRAGMENT_ENTRY *)fragMemGet(portInx,size)) == NULL)
        return ERROR;

    /* put the pre-allocated free entries to the list */

    for (j = 0; j < numOfEntries; j++)
        {
        (pEntry + j)->flag = ENTRY_IN_USE;
        dllAdd(&pFragResrcDesc[portInx]->fragFreeList,
                     &(pEntry + j)->u.node);
        }
    return OK;
    }

/****************************************************************************
*
* natFragTranModuleInit - Initialize this fragment handling module 
*
* This routine initializes and allocates the memory resources required for
* the NAT fragment handling.
*
* RETURNS: resource handler or NULL if fail
*/

void * natFragTranModuleInit (void)
    {
    int portInx;

    for (portInx = 0; portInx < 2; portInx++)
	{
	dllInit(&pFragResrcDesc[portInx]->fragFreeList);
	dllInit(&pFragResrcDesc[portInx]->memList);
        pFragResrcDesc[portInx]->outstandingEntries = 0;

	/* allocate a chunk of memory for the entry array used as the cache */

        pFragResrcDesc[portInx]->pArray = (NAT_FRAGMENT_ENTRY *)fragMemGet(
		  portInx,(sizeof(NAT_FRAGMENT_ENTRY)) * FRAG_CACHE_ARRAY_LEN);

        if (pFragResrcDesc[portInx]->pArray == NULL)
            return NULL;

        /* create the pre-allocated free entries and put to the list */

        if (fragFreeTranEntryAdd(portInx,FRAG_PREALLOC_ENTRY_NUM) != OK)
            return (NULL);
        }
    return ((void *)(&pFragResrcDesc[0]));
    }       

/****************************************************************************
*
* natFragTranCleanup - Free the resource allocated for this module
*
* This routine frees the allocated memory resources for this module 
*
* RETURNS: NONE 
*/

void natFragTranCleanup 
    (
    void * pResrcHandle
    )
{
	int portInx;
	NAT_FRAG_MEM_RESOURCE * pResource;
	NAT_FRAGMENT_RESOURCE_DESC ** pResrcDesc;

	pResrcDesc = (NAT_FRAGMENT_RESOURCE_DESC **)pResrcHandle;

	for (portInx = 0; portInx < 2; portInx++)
	{
		while ((pResource = (NAT_FRAG_MEM_RESOURCE *)dllGet(
		&pResrcDesc[portInx]->memList)) != NULL)
		free(pResource->pMem);
	}
}

/***************************************************************************
*
* natFragTranEntryGet - Get a fragment translation entry
*
* This routine first check whether the cache entry is available. If it does,
* The cache entry is returned. If it does not, it get one from the free entry
* list. 
* 
* RETURNS: the translation entry pointer or NULL if fail
*/

void * natFragTranEntryGet 
    (
    enum NAT_PORT_TYPE portType, /* Global or local port type */
    IP_PACKET * pIpPacket        /* fragment packet */
    )
    {
    int inx;
    NAT_FRAGMENT_ENTRY * pEntry;
    NAT_FRAGMENT_ENTRY * pNewEntry;
    int portInx;

    /* fragment coming from global port or local ports */

    portInx = portType == NAT_GLOBAL_PORT? GLOBAL_PORT_INX: LOCAL_PORTS_INX;

    /* index to cache entry */

    inx = pIpPacket->header.identifier & FRAG_ID_HASH_MASK;
    pEntry = &pFragResrcDesc[portInx]->pArray[inx];

    /* check if the cache entry is available */

    if (!(pEntry->flag & ENTRY_IN_USE))
        {
	/* available, save the fragment identification info */
 
        pEntry->orgSrcAddr = pIpPacket->header.source_address;
        pEntry->orgDstAddr = pIpPacket->header.destination_address;
        pEntry->fragId     = pIpPacket->header.identifier; 
        pEntry->ttl        = pIpPacket->header.time_to_live;
        pEntry->proto      = pIpPacket->header.protocol;
        pEntry->flag       = ENTRY_IN_USE;

        DBG_PRINT(("Cache Entry: inx=0x%x, srcAdr=0x%x, dstAdr=0x%x, id=0x%x\n",
                  inx,(int)pEntry->orgSrcAddr,(int)pEntry->orgDstAddr,
		  (int)pEntry->fragId));

        }
    else
        {
        /* not available, get a entry from the free list */

        if ((pNewEntry = (NAT_FRAGMENT_ENTRY *)dllGet(
		     &pFragResrcDesc[portInx]->fragFreeList)) == NULL)
            {
            /* no more free entries, unlikely, resupply it */

            if (fragFreeTranEntryAdd(portInx,16) != OK)
                return (NULL);

            pNewEntry = (NAT_FRAGMENT_ENTRY *)dllGet(
			    &pFragResrcDesc[portInx]->fragFreeList);
            }

	/* save the fragment identification info */

        pNewEntry->orgSrcAddr = pIpPacket->header.source_address;
        pNewEntry->orgDstAddr = pIpPacket->header.destination_address;
        pNewEntry->fragId     = pIpPacket->header.identifier;
        pNewEntry->ttl        = pIpPacket->header.time_to_live;
        pNewEntry->proto      = pIpPacket->header.protocol;

	/* put to the list associated with the cache entry, so it can be 
	 * easily searched by the subsequenct fragments of the datagram.
	 */

        dllAdd(&pEntry->u.list,&pNewEntry->u.node);
        pEntry = pNewEntry;
        DBG_PRINT(("list Entry: inx=0x%x, srcAdr=0x%x, dstAdr=0x%x, id=0x%x\n",
                  inx,(int)pEntry->orgSrcAddr,(int)pEntry->orgDstAddr,
		  pEntry->fragId));
        }
    pFragResrcDesc[portInx]->outstandingEntries++;
    return (void *)pEntry;
    }

/******************************************************************************
*
* fragTranIdMatch - Match the fragment from the same datagram
*
* RETURNS: the translation entry pointer or NULL if not found
*
*/

LOCAL NAT_FRAGMENT_ENTRY * fragTranIdMatch
    (
    NAT_FRAGMENT_ENTRY * pEntry,  /* The fragment cache translation entry */
    IP_PACKET * pIpPacket         /* The fragment packet to match */
    )
    {
    while (pEntry)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -