Reply To: Redirection (Gateway)

Home Forums Discussions Support Portal Redirection (Gateway) Reply To: Redirection (Gateway)

#5969

Vadim Smirnov
Moderator

Can you provide some C code for this purpose ?

The routine below is taken from the Internet Gateway source and implements NAT processing:

unsigned __stdcall CsnatDlg::StartNAT ( void* pArguments )
{
CsnatDlg* pDlg = (CsnatDlg*)pArguments;
HANDLE hEvents[ADAPTER_LIST_SIZE + 1];
CNetworkInterface* hAdapters [ADAPTER_LIST_SIZE + 1];
CNetworkInterface *pNetCard, *pProviderCard;
unsigned dwActiveAdaptersCount = 1;
ADAPTER_MODE Mode;
ETH_REQUEST Request;
INTERMEDIATE_BUFFER PacketBuffer;
DWORD dwWait, dwIndex;
ether_header* pEthHeader;
iphdr* pIpHeader;
tcphdr* pTcpHeader;
udphdr* pUdpHeader;

Mode.dwFlags = MSTCP_FLAG_SENT_TUNNEL|MSTCP_FLAG_RECV_TUNNEL;

hEvents[0] = pDlg->m_hNATTerminateEvent;

// Walk adapters list and initialize provider and clients interfaces
POSITION pos = pDlg->m_NetCardsList.GetHeadPosition();

for (unsigned i = 0; i < pDlg->m_dwAdapterCount; ++i)
{
pNetCard = (CNetworkInterface*)pDlg->m_NetCardsList.GetNext(pos);

if ((pNetCard->m_NATState == CLIENT) || (pNetCard->m_NATState == PROVIDER))
{
hAdapters[dwActiveAdaptersCount] = pNetCard;
hEvents[dwActiveAdaptersCount] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
pDlg->m_NdisApi.SetPacketEvent(pNetCard->m_hAdapter, hEvents[dwActiveAdaptersCount]);
Mode.hAdapterHandle = pNetCard->m_hAdapter;
pDlg->m_NdisApi.SetAdapterMode(&Mode);
dwActiveAdaptersCount++;

if(pNetCard->m_NATState == PROVIDER)
pProviderCard = pNetCard;
}
}

// Initialize Request
ZeroMemory ( &Request, sizeof(ETH_REQUEST) );
ZeroMemory ( &PacketBuffer, sizeof(INTERMEDIATE_BUFFER) );
Request.EthPacket.Buffer = &PacketBuffer;

do
{
dwWait = ::WaitForMultipleObjects(
dwActiveAdaptersCount,
hEvents,
FALSE,
INFINITE
);

dwIndex = dwWait - WAIT_OBJECT_0;

if (!dwIndex)
continue;

::ResetEvent(hEvents[dwIndex]);

Request.hAdapterHandle = hAdapters[dwIndex]->m_hAdapter;

// Read all queued packets from the specified interface
while(pDlg->m_NdisApi.ReadPacket(&Request))
{
pEthHeader = (ether_header*)PacketBuffer.m_IBuffer;
if ( ntohs(pEthHeader->h_proto) == ETH_P_IP )
{
pIpHeader = (iphdr*)(PacketBuffer.m_IBuffer + ETHER_HEADER_LENGTH);

// Check if connection is established from local system (we don't do NAT processing
// for local system)
BOOL bIsLocalAddress = hAdapters[dwIndex]->IsLocalAddress(&pIpHeader->ip_src);

if (bIsLocalAddress && (PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_SEND))
{
// Place packet on the network interface
pDlg->m_NdisApi.SendPacketToAdapter(&Request);

continue;
}

// TCP packet processing
if (pIpHeader->ip_p == IPPROTO_TCP)
{
// This is TCP packet, get TCP header pointer
pTcpHeader = (tcphdr*)(((PUCHAR)pIpHeader) + sizeof(DWORD)*pIpHeader->ip_hl);

// Outgoing TCP packets processing
if ((hAdapters[dwIndex]->m_NATState == PROVIDER)&&
(PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_SEND))
{
CPortNATEntry* pTcpNE = NULL;

if (pTcpHeader->th_flags == TH_SYN)
{
// New TCP connnection established, allocate dynamic NAT entry
pTcpNE = pDlg->m_TcpNatTable.Allocate(pIpHeader->ip_src, pTcpHeader->th_sport, pIpHeader->ip_dst, pTcpHeader->th_dport);

if(pTcpNE)
{
pTcpNE->m_IpNAT = hAdapters[dwIndex]->m_NATIp;
}
}
else
{
// Try to locate xisting NAT entry
pTcpNE = pDlg->m_TcpNatTable.Find(pIpHeader->ip_src, pTcpHeader->th_sport, pIpHeader->ip_dst, pTcpHeader->th_dport);
}

if (pTcpNE)
{
// If NAT entry is found perform NAT processing
pIpHeader->ip_src.S_un.S_addr = htonl(pTcpNE->m_IpNAT.S_un.S_addr);
pTcpHeader->th_sport = htons(pTcpNE->m_usNATPort);
// Recalculate checksums
RecalculateTCPChecksum (&PacketBuffer);
RecalculateIPChecksum(pIpHeader);
}
}

// Incoming TCP packets processing
if ((hAdapters[dwIndex]->m_NATState == PROVIDER)&&
(PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_RECEIVE))
{
// Map connection to the NAT entry if the one exists
CPortNATEntry* pTcpNE = pDlg->m_TcpNatTable.Map(pTcpHeader->th_dport);
if (pTcpNE)
{
// NAT entry exists, make NAT processing
if (htonl(pTcpNE->m_IpDst.S_un.S_addr) == pIpHeader->ip_src.S_un.S_addr)
{
pIpHeader->ip_dst.S_un.S_addr = htonl(pTcpNE->m_IpSrc.S_un.S_addr);
pTcpHeader->th_dport = htons(pTcpNE->m_usSrcPort);
RecalculateTCPChecksum (&PacketBuffer);
RecalculateIPChecksum(pIpHeader);
}
}

}
}
// UDP packets processing
if (pIpHeader->ip_p == IPPROTO_UDP)
{
// This is UDP packet, get UDP header pointer
pUdpHeader = (udphdr*)(((PUCHAR)pIpHeader) + sizeof(DWORD)*pIpHeader->ip_hl);

// DNS hook
// If we receive DNS packet on the NAT client adapter then we redirect it
// to this system configured DNS server
if ((hAdapters[dwIndex]->m_NATState == CLIENT)&&
(PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_RECEIVE))
{
if (ntohs(pUdpHeader->th_dport) == 53/*DNS port*/)
{
// Save the DNS IP used by the NAT client system
hAdapters[dwIndex]->m_LocalDNS.S_un.S_addr = ntohl(pIpHeader->ip_dst.S_un.S_addr);
pIpHeader->ip_dst.S_un.S_addr = pDlg->m_DNSIp.S_un.S_addr;
RecalculateIPChecksum(pIpHeader);
}
}
// DNS reply came, substitute source IP back to the original DNS address
if ((hAdapters[dwIndex]->m_NATState == CLIENT)&&
(PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_SEND))
{
if (ntohs(pUdpHeader->th_sport) == 53/*DNS port*/)
{
pIpHeader->ip_src.S_un.S_addr = htonl(hAdapters[dwIndex]->m_LocalDNS.S_un.S_addr);
RecalculateIPChecksum(pIpHeader);
}
}
// Outgoing UDP NAT processing
if ((hAdapters[dwIndex]->m_NATState == PROVIDER)&&
(PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_SEND))
{
CPortNATEntry* pUdpNE = NULL;
// Try to find existing entry
pUdpNE = pDlg->m_UdpNatTable.Find(pIpHeader->ip_src, pUdpHeader->th_sport, pIpHeader->ip_dst, pUdpHeader->th_dport);
// If not found -> allocate a new one
if (!pUdpNE)
{
pUdpNE = pDlg->m_UdpNatTable.Allocate(pIpHeader->ip_src, pUdpHeader->th_sport, pIpHeader->ip_dst, pUdpHeader->th_dport);

if(pUdpNE)
{
pUdpNE->m_IpNAT = hAdapters[dwIndex]->m_NATIp;
}
}
// NAT processing
if (pUdpNE)
{
pIpHeader->ip_src.S_un.S_addr = htonl(pUdpNE->m_IpNAT.S_un.S_addr);
pUdpHeader->th_sport = htons(pUdpNE->m_usNATPort);
RecalculateUDPChecksum (&PacketBuffer);
RecalculateIPChecksum(pIpHeader);
}
}
// Incoming UDP packets processing
if ((hAdapters[dwIndex]->m_NATState == PROVIDER)&&
(PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_RECEIVE))
{
CPortNATEntry* pUdpNE = pDlg->m_UdpNatTable.Map(pUdpHeader->th_dport);
if (pUdpNE)
{
if (htonl(pUdpNE->m_IpDst.S_un.S_addr) == pIpHeader->ip_src.S_un.S_addr)
{
pIpHeader->ip_dst.S_un.S_addr = htonl(pUdpNE->m_IpSrc.S_un.S_addr);
pUdpHeader->th_dport = htons(pUdpNE->m_usSrcPort);
RecalculateUDPChecksum (&PacketBuffer);
RecalculateIPChecksum(pIpHeader);
}
}

}
}

}

// Reinject packet into the stack
if (PacketBuffer.m_dwDeviceFlags == PACKET_FLAG_ON_SEND)
{
// Place packet on the network interface
pDlg->m_NdisApi.SendPacketToAdapter(&Request);
}
else
{
// Indicate packet to MSTCP
pDlg->m_NdisApi.SendPacketToMstcp(&Request);
}
}

}while (dwIndex);

// Free all NAT entries
pDlg->m_TcpNatTable.RemoveAll();
pDlg->m_UdpNatTable.RemoveAll();

for (unsigned i = 1; i < dwActiveAdaptersCount; ++i)
{
Mode.dwFlags = 0;
Mode.hAdapterHandle = hAdapters->m_hAdapter;

// Set NULL event to release previously set event object
pDlg->m_NdisApi.SetPacketEvent(hAdapters
->m_hAdapter, NULL);

// Close Event
if (hEvents
)
CloseHandle ( hEvents
);

// Set default adapter mode
pDlg->m_NdisApi.SetAdapterMode(&Mode);

// Empty adapter packets queue
pDlg->m_NdisApi.FlushAdapterPacketQueue (hAdapters
->m_hAdapter);
}

_endthreadex( 0 );
return 0;
}

Complete source code for the Internet Gateway is available to registered WinpkFilter customers.