📄 natpkt.c
字号:
IPDst = RdNet32( &pIpHdr->dwIPDst );
// If destination isn't us, or the source isn't from outside the
// targeted subnet, return
if( IPDst != NatIpServer || (IPSrc&NatIpMask) == NatIpAddr )
return(0);
// Get the length of the IP header
IPHdrLen = (pIpHdr->VerLen & 0xf) * 4;
// Translation varies slightly by protocol
if( pIpHdr->Protocol == IPPROTO_TCP )
{
// TCP Packet Translation
// Get TCP packet header
pTcpHdr = (TCPHDR *)(((UINT8 *)pIpHdr) + IPHdrLen);
pPortDst = &pTcpHdr->DstPort;
pChecksum = &pTcpHdr->TCPChecksum;
PortSrc = HNC16( pTcpHdr->SrcPort );
}
else if( pIpHdr->Protocol == IPPROTO_UDP )
{
// UDP Packet Translation
UDPHDR *pUdpHdr;
// Get UDP packet header
pUdpHdr = (UDPHDR *)(((UINT8 *)pIpHdr) + IPHdrLen);
pPortDst = &pUdpHdr->DstPort;
pChecksum = &pUdpHdr->UDPChecksum;
PortSrc = HNC16( pUdpHdr->SrcPort );
}
else if( pIpHdr->Protocol == IPPROTO_ICMP )
{
// ICMP Packet Translation
ICMPHDR *pIcHdr;
uint tmp;
// Get ICMP packet header
pIcHdr = (ICMPHDR *)(((UINT8 *)pIpHdr) + IPHdrLen);
// First see if this is an ICMP error packet
tmp = (uint)pIcHdr->Type;
if( tmp==ICMP_UNREACH || tmp==ICMP_SOURCEQUENCH || tmp==ICMP_REDIRECT
|| tmp==ICMP_TIMXCEED || tmp==ICMP_PARAMPROB )
return( NatIcmpError( hPkt, pIpHdr ) );
// Here we only translate ECHO and TSTAMP replies
if( tmp != ICMP_ECHOREPLY && tmp != ICMP_TSTAMPREPLY )
return( 0 );
pPortDst = (UINT16 *)pIcHdr->Data;
pChecksum = &pIcHdr->Checksum;
PortSrc = 0;
}
else
return(0);
// Get dest port
PortDst = *pPortDst;
PortDst = HNC16(PortDst);
if( !PortDst )
return(0);
nats.dwRxQualified++;
// Find a NATINFO entry
pni = NatFindPNI( 0, 0, IPSrc, PortSrc, pIpHdr->Protocol, PortDst );
// If no NATINFO, return
if( !pni )
return(0);
// Alter the destination IP and port
nats.dwRxAltered++;
// Change PortDst to be the NEW dest port
PortDst = HNC16( pni->PortLocal );
// Track changes for checksum modification (ICMP doesn't use IP address)
if( pIpHdr->Protocol != IPPROTO_ICMP )
CkMod = NatCkMod( IPDst, *pPortDst, pni->IPLocal, PortDst );
else
CkMod = NatCkMod( 0, *pPortDst, 0, PortDst );
// Alter the packet
WrNet32( &pIpHdr->dwIPDst, pni->IPLocal );
*pPortDst = PortDst;
// Adjust the TCP/UDP/ICMP checksum
CkOrg = (UINT32) ~*pChecksum;
CkOrg += CkMod;
CkOrg = (CkOrg&0xFFFF) + (CkOrg>>16);
CkOrg = ~CkOrg;
*pChecksum = (UINT16)CkOrg;
// Set new NAT record timeout value
if( pIpHdr->Protocol == IPPROTO_TCP )
NatTcpTimeout( pni, pTcpHdr );
else
pni->Timeout = llTimerGetTime(0) + NAT_IDLE_SECONDS;
// The packet is now "from" us (local IF)
// This suspends normal error checks for looping packets
PktSetIFRx( hPkt, 0 );
//
// If this entry has a "proxy", we always consume the packet.
// The proxy will forward any new packets directly to IP
//
if( pni->hProxyEntry )
{
ProxyRx( pni, hPkt, pIpHdr );
return(-1);
}
return(1);
}
//--------------------------------------------------------------------
// NatIcmpError - NAT Processing of ICMP Error packets
//
// Here, we are only interested ICMP error packets, where the header
// of the offending IP datagram is attached.
//
// If this function returns 1, the packet should be re-forwarded
//--------------------------------------------------------------------
static int NatIcmpError( HANDLE hPkt, IPHDR *pIpHdr )
{
uint IPHdrLen;
ICMPHDR *pIcHdr;
uint icmpsize;
IPHDR *pIpHdr2;
NATINFO *pni;
UINT16 PortDst;
UINT16 *pPortDst;
// Get Pointer to protocol header
IPHdrLen = (pIpHdr->VerLen & 0xf) * 4;
pIcHdr = (ICMPHDR *)(((UINT8 *)pIpHdr) + IPHdrLen);
// Get the total length of the ICMP message
icmpsize = (uint)(HNC16( pIpHdr->TotalLen )) - IPHdrLen;
// The only packets that we process is where the OFFENDING packet
// was sent from a translated source.
pIpHdr2 = (IPHDR *)(pIcHdr->Data + 4);
IPHdrLen = (pIpHdr2->VerLen & 0xf) * 4;
// Translation varies slightly by protocol
if( pIpHdr2->Protocol == IPPROTO_TCP || pIpHdr2->Protocol == IPPROTO_UDP )
{
// TCP/UDP Packet Translation
TCPHDR *pTcpHdr;
// Get TCP packet header
pTcpHdr = (TCPHDR *)(((UINT8 *)pIpHdr2) + IPHdrLen);
pPortDst = &pTcpHdr->SrcPort;
}
else if( pIpHdr->Protocol == IPPROTO_ICMP )
{
// ICMP Packet Translation
ICMPHDR *pIcHdr2;
// Get ICMP packet header
pIcHdr2 = (ICMPHDR *)(((UINT8 *)pIpHdr2) + IPHdrLen);
// We only translate ECHO and TSTAMP requests
if( pIcHdr2->Type != ICMP_ECHO && pIcHdr2->Type != ICMP_TSTAMP )
return(0);
pPortDst = (UINT16 *)pIcHdr2->Data;
}
else
return(0);
// Get dest port
PortDst = *pPortDst;
PortDst = HNC16(PortDst);
if( !PortDst )
return(0);
nats.dwRxQualified++;
// Find a NATINFO entry
pni = NatFindPNI( 0, 0, 0, 0, pIpHdr2->Protocol, PortDst );
// If no NATINFO, return
if( !pni )
return(0);
// Alter the source IP and port in the OFFENDING header, and
// the DstIP in the real IP header
nats.dwRxAltered++;
// Alter the packet
WrNet32( &pIpHdr->dwIPDst, pni->IPLocal );
WrNet32( &pIpHdr2->dwIPSrc, pni->IPLocal );
*pPortDst = HNC16(pni->PortLocal);
// Note: We won't alter the NAT entry timeout since we don't track
// the original protocol here. Plus an error isn't exactly
// active use of the entry.
// Since this function is called infrequently, we'll
// just re-checksum the whole packet.
ICMPChecksum( pIcHdr, icmpsize );
// The packet is now "from" us (local IF)
// This suspends normal error checks for looping packets
PktSetIFRx( hPkt, 0 );
return(1);
}
//--------------------------------------------------------------------
// NatTcpTimeout()
//
// Sets a reasonable TCP timeout based on a guess at the current
// TCP state. Note: We only care about keeping the normal established
// state open for a long period of time. Once a FIN or RST is
// detected, the connect is expected to remain relatively active
// until fully closed. I.E.: Idle half closed sessions are not kept.
//--------------------------------------------------------------------
static void NatTcpTimeout( NATINFO *pni, TCPHDR *pTcpHdr )
{
switch( pni->TcpState )
{
case NI_TCP_CLOSED:
if( (pTcpHdr->Flags & (SYN|FIN|RST)) == SYN )
pni->TcpState = NI_TCP_SYNSENT;
break;
case NI_TCP_SYNSENT:
if( (pTcpHdr->Flags & (SYN|FIN|RST|ACK)) == ACK )
{
pni->TcpState = NI_TCP_ESTAB;
// Maintain stats
nats.dwLongTerm++;
if( nats.dwLongTerm > nats.dwMaxLongTerm )
nats.dwMaxLongTerm = nats.dwLongTerm;
}
else if( pTcpHdr->Flags & (RST|FIN) )
pni->TcpState = NI_TCP_CLOSED;
break;
case NI_TCP_ESTAB:
if( pTcpHdr->Flags & (RST|FIN) )
{
pni->TcpState = NI_TCP_CLOSED;
// Maintain stats
nats.dwLongTerm--;
}
break;
}
pni->Timeout = llTimerGetTime(0) + StateTimeout[ pni->TcpState ];
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -