Click here to Skip to main content
15,896,912 members
Articles / Desktop Programming / MFC

Enhance netstat

Rate me:
Please Sign up or sign in to vote.
4.64/5 (11 votes)
16 Nov 2003 137.7K   3.8K   36  
This article shows an implementation of the main TCP/UDP functions of the IP Helper API that is used to get info about active connections including the process attached to a connection.
// TCPTable.cpp: implementation of the CTCPTable class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ENetStat.h"
#include "TCPTable.h"
#include "Base.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
//init static members
MIB_TCPTABLE*	 CTCPTable::m_pTcpTable = NULL;
MIB_TCPTABLE_EX* CTCPTable::m_pTcpTableEx = NULL;
BYTE*			 CTCPTable::m_pBuff = NULL;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////								  
CTCPTable::CTCPTable()
{
	m_pTcpTable = NULL;
	m_pTcpTableEx = NULL;
	m_bEstb = false;
}
//////////////////////////////////////////////////////////////////////
//
CTCPTable::~CTCPTable()
{
	delete [] m_pBuff;
}
//////////////////////////////////////////////////////////////////////
//
u_int CTCPTable::GetRecordsNumber()
{
	return 1;
}
//////////////////////////////////////////////////////////////////////
//
TCPTABLE CTCPTable::GetTableAtIndex(int nIndex)
{
	return m_tcpTab;
}
//////////////////////////////////////////////////////////////////////
//
DWORD CTCPTable::PrintTable(void)
{
	//vars
	DWORD dwSize = 0;
	in_addr stAddr;
	in_addr stAddrRem;
	CString str = " ";
	CString line = " ";
	int nSpace = 0;

		//get the buff size
		 GetTcpTable(NULL, &dwSize, FALSE);

		//alloc buffer
		m_pBuff = new BYTE[dwSize];

		//gathering info
		if (GetTcpTable((PMIB_TCPTABLE)m_pBuff, &dwSize, TRUE) != NO_ERROR)
		{
			TRACE("Error: %d, gathering tcp info");
			return GetLastError();
		}
		
		//manage the buffer
		m_pTcpTable = (PMIB_TCPTABLE)m_pBuff;

		//print the info
		printf("\n Proto \tLocal Address            Local Port     Remote Address           Remote Port \tConnection State");

		for (int i = 0; i < m_pTcpTable->dwNumEntries; i++)
		{
			//prepare the local address field
			u_long ulLocalAddress = static_cast<u_long>(m_pTcpTable->table[i].dwLocalAddr);
			stAddr.s_addr = ulLocalAddress;	//stAddr.S_un.S_addr = stAddr.s_addr
			
			//prepare the local port field
			u_short usLocalPort = ntohs(m_pTcpTable->table[i].dwLocalPort);
			
			//prepare the remote address field
			u_long ulRemoteAddress = static_cast<u_long>(m_pTcpTable->table[i].dwRemoteAddr);
			stAddrRem.s_addr = ulRemoteAddress;
			
			//prepare the local port field
			u_short usRemotePort = ntohs(m_pTcpTable->table[i].dwRemotePort);
			
			if ((m_bEstb == true) && (m_pTcpTable->table[i].dwState == MIB_TCP_STATE_ESTAB))
			{	
				//print info for locals
				printf("\n TCP\t%s ", inet_ntoa(stAddr));
				str = inet_ntoa(stAddr);
				nSpace = str.GetLength();
				for (; nSpace <= 16; nSpace++) printf(" ");
				printf("\t %u", usLocalPort);
				str.Empty();
				//printf("\n TCP\t%s \t%u", inet_ntoa(stAddr), usLocalPort);
				
				//print info for remote
				printf(" \t\t%s", inet_ntoa(stAddrRem));
				str = inet_ntoa(stAddrRem);
				nSpace = str.GetLength();
				for (; nSpace <= 16; nSpace++) printf(" ");
				printf("\t %u", usRemotePort);
				//printf("\t\t%s \t%u", inet_ntoa(stAddrRem), usRemotePort);
				
				//print info for state
				printf("\t\t%s", Convert2State(m_pTcpTable->table[i].dwState));
			}
			else if(m_bEstb == false)
			{
				//print info for locals
				printf("\n TCP\t%s ", inet_ntoa(stAddr));
				str = inet_ntoa(stAddr);
				nSpace = str.GetLength();
				for (; nSpace <= 16; nSpace++) printf(" ");
				printf("\t %u", usLocalPort);
				str.Empty();
				//printf("\n TCP\t%s \t%u", inet_ntoa(stAddr), usLocalPort);
				
				//print info for remote
				printf(" \t\t%s", inet_ntoa(stAddrRem));
				str = inet_ntoa(stAddrRem);
				nSpace = str.GetLength();
				for (; nSpace <= 16; nSpace++) printf(" ");
				printf("\t %u", usRemotePort);
				//printf("\t\t%s \t%u", inet_ntoa(stAddrRem), usRemotePort);
				
				//print info for state
				printf("\t\t%s", Convert2State(m_pTcpTable->table[i].dwState));
			}			
		}

	return 1;
}
//////////////////////////////////////////////////////////////////////
//
DWORD CTCPTable::PrintTableEx(void)
{
	//vars
	HMODULE hmModule = NULL;
	in_addr stAddr;
	in_addr stAddrRem;
	DWORD dwSize = 0;		
	CBase *pBase = new CBase();
	CString strPath;

	//imported method
	pAllocateAndGetTcpExTableFromStack pGetTcpTableEx = NULL;
	
	if(pBase != NULL)
	{
		//prepare the path
		strPath = pBase->GetSysPath() + "\\system32\\iphlpapi.dll";

		//release unused objects
		delete pBase;
		pBase = NULL;
	}

	//load "iphlpapi.dll"
	hmModule = ::LoadLibrary(strPath);
	if(hmModule == NULL)
		return ::GetLastError();

	//alloc buff
	PMIB_TCPTABLE_EX m_pBuffTcpTableEx;

	//point to the magic method
	pGetTcpTableEx = (pAllocateAndGetTcpExTableFromStack) GetProcAddress(
		hmModule, "AllocateAndGetTcpExTableFromStack");
	if(pGetTcpTableEx == NULL)
		return ::GetLastError();

	//gathering info
	(pGetTcpTableEx) (&m_pBuffTcpTableEx, TRUE, GetProcessHeap(), 0, 2);

	//print the info
	printf("\n Proto \tPid \tProcess Name \tLocal Address \tLocal Port \tRemote Address \tRemote Port \tConnection State");
	for (int i = 0; i < m_pBuffTcpTableEx->dwNumEntries; i++)
	{
		//prepare the local address field
		u_long ulLocalAddress = static_cast<u_long>(m_pBuffTcpTableEx->table[i].dwLocalAddr);
		stAddr.s_addr = ulLocalAddress;	//stAddr.S_un.S_addr = stAddr.s_addr

		//prepare the local port field
		u_short usLocalPort = ntohs(m_pBuffTcpTableEx->table[i].dwLocalPort);

		//prepare the remote address field
		u_long ulRemoteAddress = static_cast<u_long>(m_pBuffTcpTableEx->table[i].dwRemoteAddr);
		stAddrRem.s_addr = ulRemoteAddress;

		//prepare the local port field
		u_short usRemotePort = ntohs(m_pBuffTcpTableEx->table[i].dwRemotePort);

		//prepare the Pid
		DWORD dwPid = m_pBuffTcpTableEx->table[i].dwProcessId;

		CString strProcName = pBase->GetProcById(m_pBuffTcpTableEx->table[i].dwProcessId);

		if ((m_bEstb == true) && (m_pBuffTcpTableEx->table[i].dwState == MIB_TCP_STATE_ESTAB))
		{		
			Conn2Console(dwPid,strProcName,inet_ntoa(stAddr),usLocalPort,inet_ntoa(stAddrRem),usRemotePort);
			printf("\t\t%s", Convert2State(m_pBuffTcpTableEx->table[i].dwState));
		}
		else if(m_bEstb == false)
		{
			Conn2Console(dwPid,strProcName,inet_ntoa(stAddr),usLocalPort,inet_ntoa(stAddrRem),usRemotePort);			//print info for state
			printf("\t\t%s", Convert2State(m_pBuffTcpTableEx->table[i].dwState));
		}
	}

	if (0 == FreeLibrary(hmModule))
		return ::GetLastError();

	return 1;
}
//////////////////////////////////////////////////////////////////////
//
bool CTCPTable::KillConnection(u_long ulRemIP, u_short usLocalPort)
{
	u_long ulLocIP = 0;
	u_short usRemPort = 0;
	MIB_TCPROW sKillConn;

	if (false == GetMatchingConn(ulRemIP, usLocalPort, &ulLocIP, &usRemPort))
	{
		printf("\n Error closing connection ;(\n");
		return false;
	}

	sKillConn.dwLocalAddr	= (DWORD)ulLocIP;
	sKillConn.dwLocalPort	= (DWORD)usLocalPort;
	sKillConn.dwRemoteAddr	= (DWORD)ulRemIP;
	sKillConn.dwRemotePort	= (DWORD)usRemPort;
	sKillConn.dwState = MIB_TCP_STATE_DELETE_TCB;
	
	DWORD dwRez = SetTcpEntry(&sKillConn);
	if(dwRez != NO_ERROR)
	{
		dwRez = ::GetLastError();
		printf("\nError closing connection ;(\n");
		return false;
	}
	
	printf("\nConnection closed succesfully ;)\n");
	
	return true;
}
//////////////////////////////////////////////////////////////////////
//
CString	CTCPTable::Convert2State(DWORD dwState)
{
	switch(dwState)
	{
		case MIB_TCP_STATE_CLOSED:
			return "CLOSED";
		
		case MIB_TCP_STATE_LISTEN:
			return "LISTEN";

		case MIB_TCP_STATE_SYN_SENT:
			return "SYN_SENT";

		case MIB_TCP_STATE_SYN_RCVD:
			return "SYN_RCVD";

		case MIB_TCP_STATE_ESTAB:
			return "ESTAB";

		case MIB_TCP_STATE_FIN_WAIT1:
			return "FIN_WAIT1";

		case MIB_TCP_STATE_FIN_WAIT2:
			return "FIN_WAIT2";

		case MIB_TCP_STATE_CLOSE_WAIT:
			return "CLOSE_WAIT";

		case MIB_TCP_STATE_CLOSING:
			return "CLOSING";

		case MIB_TCP_STATE_LAST_ACK:
			return "LAST_ACK";

		case MIB_TCP_STATE_TIME_WAIT:
			return "TIME_WAIT";

		case MIB_TCP_STATE_DELETE_TCB:
			return "DELETE_TCB";

		default:
			return "UNKNOWN";
	}
}
//////////////////////////////////////////////////////////////////////
//	
void CTCPTable::Conn2Console(DWORD	 dwPid, \
							 CString strProcName, \
							 CString strLocAddress, \
							 u_short usLocalPort, \
							 CString strRemAddress, \
							 u_short usRemotePort)
{
	//print info for locals
	printf("\n TCP \t%d \t%s  \t%s \t%u", dwPid, strProcName, strLocAddress, usLocalPort);
	//print info for remote
	printf("\t\t%s \t%u", strRemAddress, usRemotePort);	
}
//////////////////////////////////////////////////////////////////////
//
bool CTCPTable::GetMatchingConn(u_long ulRemAdr, u_short usLocPort, u_long* ulLocAdr, u_short* usRemPort)
{
	//vars
	DWORD dwSize = 0;
	
	*ulLocAdr = 0;
	*usRemPort= 0;

	//get the buff size
	GetTcpTable(NULL, &dwSize, FALSE);
	
	//alloc buffer
	m_pBuff = new BYTE[dwSize];
	
	//gathering info
	if (GetTcpTable((PMIB_TCPTABLE)m_pBuff, &dwSize, TRUE) != NO_ERROR)
	{
		TRACE("Error: %d, gathering tcp info");
		return false;
	}
	
	//manage the buffer
	m_pTcpTable = (PMIB_TCPTABLE)m_pBuff;
	
	for (int i = 0; i < m_pTcpTable->dwNumEntries; i++)
	{
		u_long ulLocalAddress	= (u_long)m_pTcpTable->table[i].dwLocalAddr;
		u_short usLocalPort		= m_pTcpTable->table[i].dwLocalPort;
		u_long ulRemoteAddress	= (u_long)m_pTcpTable->table[i].dwRemoteAddr;
		u_short usRemotePort	= m_pTcpTable->table[i].dwRemotePort;
		
		if ((m_pTcpTable->table[i].dwState == MIB_TCP_STATE_ESTAB) && \
			(usLocPort == usLocalPort) && \
			(ulRemAdr  == ulRemoteAddress))
		{
			*ulLocAdr  = ulLocalAddress;
			*usRemPort = usRemotePort;

			return true;
		}
	}

	return false;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Romania Romania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions