论文首页哲学论文经济论文法学论文教育论文文学论文历史论文理学论文工学论文医学论文管理论文艺术论文 |
};
7.2.2 NAT 收发处理函数的绑定
仔细分析 vxworks 协议栈代码后,觉得使用 _ipFilterHook 绑定 NAT 接收报文处理函数的方式比较可行,该钩子函数在协议栈接收到数据报文时被调用,函数输入输出格式如下:
BOOL NatIpFilterHookRtn
(
struct ifnet rcvifnet, /* 数据接收的接口*/
struct mbuf **m, /* 数据报文地址 */
struct ip **ip, /* IP 头部地址 */
int hlen /* IP 头的长度 */
)
返回值: 为 FALSE时表示报文处理正常,协议栈可继续转发或处理
为TRUE 时指示系统丢弃该报文
由于无法找到协议栈输出报文的钩子,我们打算把输出报文 NAT 转换放在 _ipFilterHook 的 LAN 口钩子中处理,即在 LAN口报文进入协议栈之前就更改源IP和端口地址。但这样做的缺点是:此时系统还没有检索过该报文的路由目的接口,需要人为增加查找路由表算法,当发现是发往指定 WAN 口时再行转换,处理的效率较低。
为充分利用协议栈的报文路由处理功能,决定采用更改协议栈代码的方式,在 ip_output 函数适当位置处人为增加一个钩子 _func_natOutput,重新编译 vxworks 协议栈库函数。 这样,NAT 模块初始化时即可将NAT输出报文处理函数绑定至该钩子。函数的输入输出关系格式如下:
int NatOutput
(
struct mbuf** m0, /* 数据报文地址 */
struct ip **ip, /* IP 头部地址 */
struct in_ifaddr* ia /* 报文目的接口 */
)
返回值: OK 或 ERROR (ERROR 时将丢弃并释放该报文)
(转载自科教范文网http://fw.nseac.com)7.3 NAT模块主要算法
7.3.1 NAT 端口地址转换HASH算法
NAPT 转换表查找算法可分为按端口查找和按地址查找两种。在实际的 ADSL接入中,局端很少会为一个连接分配多个 IP,因此我们采用按端口查找的算法来简单实现。
1) session 结构数组的初始化
NAT初始化时根据系统支持的最大转换数目建立一个按端口分布的 nat_session结构数组(nat_session 节点的定义见7.2.1), 同时建立一个指向nat_session 的空 hash 表。Hash节点结构如下:
typedef struct nat_hash_bucket_
{
struct nat_hash_bucket_ *next; //指向下一个节点
struct nat_hash_bucket_ *prev; //指向前一个节点
unsigned nat_session *pSession; //指向nat链表中相应的节点
}nat_hash_bucket;
2) 新建 session
get_free_session 在session静态表(结构数组)中获得一个free session,并将其从Hash表中unlink出来。查找的依据为时间戳, 顺序遍历session表,直到找到第一个超时的session。若未找到,则覆盖当前指针指向的session。
填充该 session 结构,返回该session 所对应的端口号。根据 TCP/UDP 报文的源 IP 和源端口号计算出 hash 头,增加到 hash 头所对应的链表后。其中,hash 头的算法如下:
LOCAL UINT16 ipnat_hash_fn(ipaddrtype addr1,
ipaddrtype addr2,
UINT16 port1,
UINT16 port2)
{
UINT16 bucket;
bucket = addr1 >> 16;
bucket ^= addr1 & 0xffff;
bucket ^= port1;
bucket ^= addr2 >> 16;
bucket ^= addr2 & 0xffff;
bucket ^= port2;
bucket = bucket % IPNAT_HASHLEN;
return(bucket);
}
转换后的 TCP/IP 报文源IP变为 WAN口IP,源端口变为session 索引值,这样做的优点是:外部返回的报文可以通过TCP/IP报文的目的端口号直接定位到 session 数组中,查找的速度最快。
3) 查找 session
通过 TCP/UDP 报文的源 IP 和源端口号计算出 hash 头,然后遍历该头所对应的链表,直到找到相匹配的hash 节点。
4) 删除 session
收到 TCP/UDP 连接关闭请求后,根据目的端口号找到 session 数组,释放该 session, 并将其从 Hash 表中 unlink 出来。
7.3.2 TCP/UDP 协议端口地址转换
setup_tcpudp_outgoing 为从内部网络出去的TCP/UDP连接建立一个session,记录下连接的源地址、端口,目标地址、端口,转换后的地址、端口,协议类型以及连接建立时间等信息。
translate_outgoing_tcpudp 核心函数,根据 session 的对应记录,转换数据包的IP地址、端口,同时重新调整IP校验和及TCP/UDP校验和,其中,校验和调整主要用到了adjust_chksum函数。算法如下:
void adjust_chksum(ulong *chkSum, ushort oldW, ushort newW)
{
*chkSum -= oldW & 0xffff;
if ((*lChkSum) <= 0)
{
(*chkSum) --;
(*chkSum) &= 0xffff;
}
(*chkSum) += newW & 0xffff;
if ((*chkSum) & 0x10000)
{
(*chkSum) ++;
(*chkSum) &= 0xffff;
}
}
8 设计
本系统的优点是,仅需采用一块 CPU 即可同时实现 ADSL接入和路由两项功能,硬件资源利用率高,而且,两种功能在同一套系统平台中可以有机结合,避免因中间插入多余转换接口导致包处理效率降低。
文中所述的仅实现了一个最简单的 ADSL 共享接入方式,并不能完全满足实际使