📄 nat_rx.c
字号:
switch (nat_packet_type)
{
case NAT_TCP:
return_code = handle_tcp_translation_global_rx ((TCP_PACKET*)p_packet);
break;
case NAT_ICMP_DATAGRAM:
return_code = handle_icmp_translation_global_rx_datagram ((ICMP_PACKET*)p_packet);
break;
case NAT_ICMP_TRANSACTION:
return_code = handle_icmp_translation_global_rx_transaction ((ICMP_PACKET*)p_packet);
break;
case NAT_RIP:
case NAT_UDP:
return_code = handle_udp_translation_global_rx ((UDP_PACKET*)p_packet);
break;
case NAT_UNKNOWN_PROTOCOL:
if (nat.filter_unknown_protocols == TRUE)
{
return_code = FAIL;
}
else
{
return_code = TRUE;
}
break;
default:
return_code = FAIL;
}
return (return_code);
}
/********************************************************************************************
This function handles translation of outbound packets (i.e. received from local port).
********************************************************************************************/
static enum TEST nat_handle_translation_for_local_rx (M_BLK* pMblk,
enum NAT_PACKET_TYPES nat_packet_type)
{
enum TEST return_code;
/* none of the following functions currently use the port_number passed */
switch (nat_packet_type)
{
case NAT_TCP:
return_code = handle_tcp_translation_local_rx (
(TCP_PACKET *) pMblk->mBlkHdr.mData);
break;
case NAT_ICMP_DATAGRAM:
return_code = handle_icmp_translation_local_rx_datagram (
(ICMP_PACKET *) pMblk->mBlkHdr.mData);
break;
case NAT_ICMP_TRANSACTION:
return_code = handle_icmp_translation_local_rx_transaction (
(ICMP_PACKET *) pMblk->mBlkHdr.mData);
break;
case NAT_RIP:
case NAT_UDP:
return_code = handle_udp_translation_local_rx (
(UDP_PACKET *) pMblk->mBlkHdr.mData);
break;
case NAT_UNKNOWN_PROTOCOL:
if (nat.filter_unknown_protocols == TRUE)
{
return_code = FAIL;
}
else
{
return_code = TRUE;
}
break;
default:
return_code = FAIL;
}
return (return_code);
}
/*************************************************************************************
Description:
Look for a registered agent (e.g. ALG) from the given NAT instance.
*************************************************************************************/
NAT_AGENT_INFO *nat_find_agent(
NAT_CLASS *nat_p,
u_short protocol,
u_long remote_port,
u_long local_port
)
{
NAT_AGENT_INFO *agent_info;
semTake(agentListLock, WAIT_FOREVER);
agent_info = (NAT_AGENT_INFO *) lstFirst(&nat.agent_list);
while (agent_info != NULL)
{
if (agent_info->session_tag.protocol == protocol &&
(agent_info->session_tag.transport == remote_port ||
agent_info->session_tag.transport == local_port))
{
nat_printf (NAT_PRINTF_TRACE,
"Registered agent found for port %d\n",
agent_info->session_tag.transport);
break;
}
agent_info = (NAT_AGENT_INFO *) lstNext((NODE*)agent_info);
}
semGive(agentListLock);
return (agent_info);
}
/******************************************************************************
*
* natIcmpErrorHookAdd - Install the NAT ICMP error handling routine
*
*/
void natIcmpErrorHookAdd (void)
{
if (_icmpErrorHook != NULL)
{
stdIcmpErrorHook = _icmpErrorHook;
_icmpErrorHook = (VOIDFUNCPTR)natIcmpErrorHook;
}
else
nat_printf (NAT_PRINTF_ERROR,
"natIcmpErrorHookAdd Error: _icmpErrorHook is NULL\n");
}
/******************************************************************************
*
* natIcmpErrorHookRemove - Remove the NAT ICMP error handling routine
*
*/
void natIcmpErrorHookRemove (void)
{
if (stdIcmpErrorHook != NULL)
_icmpErrorHook = stdIcmpErrorHook;
}
/*****************************************************************************
*
* natIcmpErrorHook - Process the ICMP error message generated by the stack
*
* This routine handles the ICMP error message generated by the NAT device's
* own IP stack on the NAT translated packets. Consider this scenario:
* a TCP/UDP packet enters the NAT device via global port, is translated by NAT,
* and is handed to the IP stack. But the IP stack can't deliver the packet to
* the local port because of an error condition (e.g., MTU size is too small
* and the don't fragment bit is set). The IP stack then constructs an
* ICMP error message (e.g., destination unreachable) with the embedded
* fragment of the offending packet. However, this fragment must be retranslated
* back to its global address before sending it out to the driver. Otherwise it
* will have incorrect local address. The same scenario can happen for a TCP/UDP
* packet coming from a NAT device's local port. In this case, if we don't
* retranslate the packet, it will possibly have the NAT device's own global
* interface address as the destination address, thus will be wrongly sent to
* the loopback interface.
*
* To solve the problem, this routine will first convert the NAT translated
* packet back to the original and then hand to the standard ICMP error handling
* routine. This requires the standard ICMP error handle hook to be
* installed with this new routine and the original one is called within
* this routine.
*
*/
void natIcmpErrorHook
(
M_BLK_ID pMblk, /* orginal IP packet */
int type, /* ICMP type */
int code, /* ICMP code */
ULONG dest,
struct ifnet *destifp
)
{
struct ifnet * pIf;
/* convert back the NAT translated packet to the original */
pIf = pMblk->m_pkthdr.rcvif;
natTranslatedIpPacketConvert(pMblk,pIf,type);
/* call the standard ICMP error handling routine */
(*stdIcmpErrorHook)(pMblk,type,code,dest,destifp);
}
/******************************************************************************
*
* natTranslatedIpPacketConvert - convert back the NAT translated packet
*
* This routine converts the NAT translated packet back to the original as if it
* was not translated. When the packet pointed to by parameter pMblk arrives at
* this function. It has already been translated by NAT filter. That means the
* packet's destination,source addresses as well as the port numbers if it
* is a TCP/UDP packet is no longer same as the ones when it came in the network
* port. These elements need to be translated back. Instead of inventing a set
* of reverse translation routines for the TCP,UDP or other packet headers, we
* find it easy to constructs an ICMP packet with necessary fields and copy the
* packet header as the payload of the ICMP packet, and then utilize existing
* NAT ICMP translation routines to perfrom the conversion.
*
* The converted packet header will be copied back to the original packet. The
* caller of this routine takes it and then call the standard ICMP error
* handling routine. And a real ICMP packet will be constructed there.
*
* This routine must also take consideration of the ICMP error messages generated
* on the packets which are not touched by the NAT translation filter, are now
* also intercepted by this new NAT ICMP error handling routine. They must not
* be erroneously translated.
*
*/
LOCAL void natTranslatedIpPacketConvert
(
M_BLK_ID pMblk, /* original IP packet */
struct ifnet * pIf, /* network interface the packet coming from */
int type
)
{
M_BLK_ID pTmpMblk;
ICMP_PACKET * pIcmpPkt;
IP_PACKET * pIpPacket;
ULONG address;
int inx;
enum NAT_PORT_TYPE icmpPortType;
enum TEST retCode;
char ifName[IF_DEV_NAME_LEN];
/* filter out non NAT related packets */
if (nat.enabled == FALSE || pIf == NULL)
return; /* no translation */
inx = 0;
while ((pIf->if_name[inx]) && (inx < (IF_DEV_NAME_LEN - 2)) )
ifName[inx] = pIf->if_name[inx++];
ifName[inx++] = '0' + pIf->if_unit;
ifName[inx++] = 0;
/* find this packet is coming from global or local interface or neither */
for (inx = 0; inx < sizeof(nat.port)/sizeof(nat.port[0]); inx++)
{
if ((nat.port[inx].ifunit == pIf) ||
((nat.port[inx].ifunit == NULL) && /* dynamically attached IF */
(strcmp(nat.port[inx].ifname,ifName)==0)) )
{
/* Found the port */
break;
}
}
if (inx == sizeof(nat.port)/sizeof(nat.port[0]))
/* no port found, the packet does not come from a NAT port */
return; /* no translation */
/* allocate a mblk to hold the temp ICMP packet */
pTmpMblk = netTupleGet(_pNetDpool, 128,M_DONTWAIT,MT_DATA,TRUE);
if (pTmpMblk == NULL)
{
nat_printf (NAT_PRINTF_ERROR,
"natIcmpErrorHook: Can't get a mblk\n");
return;
}
/* construct an incomplete ICMP header, good enough for the NAT ICMP
* translation
*/
pIcmpPkt = (ICMP_PACKET *)(pTmpMblk->mBlkHdr.mData);
bcopy((char *)pMblk->mBlkHdr.mData,(char *)&pIcmpPkt->ip_header,
sizeof(IP_HEADER));
pIcmpPkt->ip_header.protocol = IPPROTO_ICMP;
/* construct the ICMP error packet's destination and source addresses */
address = pIcmpPkt->ip_header.source_address;
pIcmpPkt->ip_header.source_address =pIcmpPkt->ip_header.destination_address;
pIcmpPkt->ip_header.destination_address = address;
pIcmpPkt->ip_header.total_length = htons(80); /* fake one */
pIcmpPkt->header.checksum = 0x1122; /* fake one */
pIcmpPkt->header.type = type;
/* The ICMP error packet generated by this NAT deivce's IP stack on the
* packet coming from the NAT global port just looks as if a ICMP error
* packet coming from the NAT local interface and vice versa, as far as
* the NAT translation filter concerns.
*/
/* so reverse the port type */
if (nat.port[inx].type == NAT_GLOBAL_PORT)
icmpPortType = NAT_LOCAL_PORT;
else
icmpPortType = NAT_GLOBAL_PORT;
/* Further checking whether this packet needs to be translated back */
if (nat_filter_rx(ntohl(pIcmpPkt->ip_header.destination_address),
inx, icmpPortType) != NAT_TRANSLATE)
{
netMblkClFree(pTmpMblk);
return; /* no translation */
}
/* copy the original IP and TCP headers */
bcopy((char *)pMblk->mBlkHdr.mData,
(char *)&pIcmpPkt->header.option.unreachable_message.ip_data,
sizeof(IP_HEADER) + sizeof(TCP_HEADER));
/* perform the translation */
if (icmpPortType == NAT_GLOBAL_PORT)
{
retCode = nat_handle_translation_for_global_rx(
(IP_PACKET *)(pTmpMblk->mBlkHdr.mData),
NAT_ICMP_DATAGRAM);
}
else
{
retCode = nat_handle_translation_for_local_rx(pTmpMblk,
NAT_ICMP_DATAGRAM);
}
if (retCode == FAIL)
{
/* again this packet is not translated by NAT, simply return */
netMblkClFree(pTmpMblk);
return;
}
/* now translation is done, copy it back to the original mblk */
bcopy((char *)&pIcmpPkt->header.option.unreachable_message.ip_data,
(char *)pMblk->mBlkHdr.mData,
sizeof(IP_HEADER) + sizeof(TCP_HEADER));
/* the IP header checksum is most likely not correct due to the fact the
* ipintr zeroed it in the default configuration. Recalculate it.
*/
pIpPacket = (IP_PACKET*) pMblk->mBlkHdr.mData;
/* The total length is already in host byte order, convert it back */
pIpPacket->header.total_length = htons(pIpPacket->header.total_length);
/* the offset is already in host byte order, convert it back */
pIpPacket->header.fragment = htons(pIpPacket->header.fragment);
/* do the checksum calculation */
pIpPacket->header.header_checksum = 0;
pIpPacket->header.header_checksum = in_cksum(pMblk,
pIpPacket->header.version_header_length.header_length << 2);
/* the icmp_error will add IP header length to the total length field
* and assume the id field is in host byte order. So we need to set proper
* values for these two fields here before feeding to the icmp_error.
*/
pIpPacket->header.total_length = ntohs(pIpPacket->header.total_length);
pIpPacket->header.total_length -=
(pIpPacket->header.version_header_length.header_length << 2);
pIpPacket->header.identifier = ntohs(pIpPacket->header.identifier);
pIpPacket->header.fragment = ntohs(pIpPacket->header.fragment);
/* free the allocated temporary mblk */
netMblkClFree(pTmpMblk);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -