Reply To: Redirection (Gateway)

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

#5969
Vadim Smirnov
Keymaster

    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.