📄 nat_rx.c
字号:
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 + -