topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • Friday March 29, 2024, 4:26 am
  • Proudly celebrating 15+ years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: Socket Handle Leak Issue  (Read 12481 times)

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Socket Handle Leak Issue
« on: April 25, 2009, 04:28 PM »
Greetings
   Just to get a few thing out of the way:
1. Yes I am working on a network scanner.
2. No it does not have any malicious intent, it's for the company I work for.
3. I'm working in pure Win32 API C++, so no MFC, .NET, VB runtime crap.

So... Here's what I got.

Code goes out & finds a certain type of device on the network, then collects information about the devices found for display to user (Standard fair for a network scanner). But, If I run the collection routine in a loop to keep the info up to date, I get an ever increasing number of "orphaned" handles, that I never created. This also happens if I only run the scan once, but the impact isn't nearly as damning.

Socket is opened and cleanly closed for each target. But the non-responsive (only...) targets leave a lingering handle (\device\afd in process explorer) that I can not access, identify, or kill.

Note: These "Handles" persist even after the scanning thread is closed.


Any Ideas on how to identify/find, close, free, kill these orphande handles???

Ehtyar

  • Supporting Member
  • Joined in 2007
  • **
  • Posts: 1,237
    • View Profile
    • Donate to Member
Re: Socket Handle Leak Issue
« Reply #1 on: April 25, 2009, 05:09 PM »
It would probably be helpful to know which functions you're using and any relevant params/structs that are used with them.

Ehtyar.

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Re: Socket Handle Leak Issue
« Reply #2 on: April 25, 2009, 09:29 PM »
Hm... That's hard to do without posting the code ... but I'll give it a shot.

There's 3 steps to the scan:
1. Raw Socket ICMP to see if the address is "live".
2. connect(...) to port X to see if target is what we want.
3. SNMP collection of relevent info.

Step 3 seems to be fine.

Step 2 toggles non-blocking & blocking arround connect(...) to let select(...) decide if target is a "go".

Step 1 (in the gutted version of the code I'm using for test) seems to be my problem child. I'm using sendto(...) (for speed) to "blindly" toss an empty (payload-less) packet "shell" up the wire, and then letting select(...) control an adjustable "clock" for the pass/fail/next decision. If a reply is returned recvfrom(...) is used to extract the timestamp so it can verify that the target is replying, and is not just a phantom response from the stack saying "Reply from self...target is down". Usually seen when pinging from Vista, LM answers for the down'd target, but the reply time is 10,000+ ms.

Structures for the packet header are all just basic by-the-book stuff.

Let me know if you ned more info, I can post a snippet or two if need be.

Thank you,
Stoic Joker

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Re: Socket Handle Leak Issue
« Reply #3 on: April 26, 2009, 10:35 AM »
Correction Step 2 is also causing issues. I had at one point thought it was an issue with my threading model, so I found a tutorial (with code samples) that showed a different ("Correct"er?) method of thread handling. I plugged my code into it in a piece by piece manner to see when/which part/if the error could be reproduced.

Unfortunately, the only thing this proved, was that my threading modle was fine... *sigh* But here are the relevent parts of the connection (Step 2) test that are causing the oprhand handle issue. Each time the code fires, the programs handle count (bizzarly)increases by one.

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
int isSocWriteable(SOCKET s) { //======================================================================
struct timeval Timeout;
fd_set writefds;
int iResult;

  writefds.fd_count = 1;
  writefds.fd_array[0] = s;    //====================== No Time to Loiter...
  Timeout.tv_usec = 42000; //(dwMIN_Reply * 1000); //========== This is Measured in Microseconds!
  Timeout.tv_sec = 0; // ^^^ Current Default is 62 Milliseconds (or 62000 Microseconds).
  iResult = select(1, NULL, &writefds, NULL, &Timeout); //========== Get the Results...
return(iResult); //========================================== ...Return the Results.
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

///////////////////////////////////////////////
// PortScannerWindow::goScan
///////////////////////////////////////////////

BOOL PortScannerWindow::goScan() {

SOCKET lhSocket; // Our socket
    SOCKADDR_IN lSockAddr; // The SOCKADDR_IN structure containing IP and port info
    WSADATA wsaData; // WinSock config data structure

    int lConnect; // Connection status flag

int StartPort;
int EndPort;
char* IPAddress;
BOOL bSuccess; // Success flag needed for GetDlgItemInt

char* buffer; // Buffer to hold updated info for the text output area
int nTxtLen;

// Get IP Address, Start Port and End Port
// Remember, we've already validated this input
IPAddress = GrabTextFromEdit(IDE_IPADDRESS);
    StartPort = GetDlgItemInt(m_hWnd,IDE_STARTPORT,&bSuccess,FALSE);
EndPort   = GetDlgItemInt(m_hWnd,IDE_ENDPORT,  &bSuccess,FALSE);

// Initialize WinSock
if(WSAStartup(MAKEWORD(2,0),&wsaData) != 0)
    {
        MessageBox(m_hWnd, "Socket Initialization Error.", "Socket Error",
MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}

// Allocate space for text output
buffer = (char*)malloc(100*sizeof(char));

// Loop through from StartPort to EndPort
for (int i=StartPort;i<=EndPort;i++) {

// Initialize Socket
    lhSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(lhSocket == INVALID_SOCKET)
    {
         MessageBox(m_hWnd, "Invalid Socket.", "Socket Error",
MB_OK | MB_ICONEXCLAMATION);
    }

  linger ls = {1, 0}; //= ABSOLUTELY NO LOITERING - Get the Answer & Slam the ***
  setsockopt(lhSocket, SOL_SOCKET, SO_LINGER, (LPSTR)&ls, sizeof(ls)); // Door Shut! ***

// Zero out SOCKADDR_IN structure
memset(&lSockAddr,0, sizeof(lSockAddr));

// Fill SOCKADDR_IN structure
lSockAddr.sin_family = AF_INET;
lSockAddr.sin_port = htons(i);
lSockAddr.sin_addr.s_addr = inet_addr(IPAddress);


/*------------------------------------------------------------->
  Set Socket I/O mode: In this case FIONBIO Enables or Disables
  the Sockets Blocking Mode Based on the Numeric Value of iMode.
  If iMode != 0, non-blocking mode is enabled.
  If iMode = 0, blocking is enabled;
<-------------------------------------------------------------*/
int iMode = 1; //====== Set Socket to NON-Blocking Mode During Connection so it
ioctlsocket(lhSocket, FIONBIO, (u_long FAR*) &iMode); // Doesn't Hold Up the Show...

// Attempt connect
lConnect = connect(lhSocket,(SOCKADDR *)&lSockAddr,sizeof(SOCKADDR_IN));

iMode = 0; //============== Switch Socket to Blocking Mode to Verify it is Writeable.
ioctlsocket(lhSocket, FIONBIO, (u_long FAR*) &iMode); //====== Socket is in Blocking Mode.

//============ Make or Break Point for Primary Question; IS Spooler Port 515 Active?!?
    if(!isSocWriteable(lhSocket))  //==================== IF it Has a Spooler, It IS a Printer!

// if(lConnect != 0)
// On connect failure:
{
// Output result of this scan
sprintf_s(buffer, 64, "%s:%d - Closed\r\n",IPAddress,i);
nTxtLen = GetWindowTextLength(GetDlgItem(m_hWnd,IDT_OUTPUT));
SendMessage(GetDlgItem(m_hWnd,IDT_OUTPUT), EM_SETSEL, nTxtLen, nTxtLen); // move caret to end
SendMessage(GetDlgItem(m_hWnd,IDT_OUTPUT), EM_REPLACESEL, 0, (LPARAM)buffer); // append text
SendMessage(GetDlgItem(m_hWnd,IDT_OUTPUT), EM_SCROLLCARET, 0, 0); // scroll to caret
} else {
// On connect success:
// Output result of this scan
sprintf_s(buffer, 64, "%s:%d - Open\r\n",IPAddress,i);
SendMessage(GetDlgItem(m_hWnd,IDT_OUTPUT), EM_SETSEL, -1, -1); // move caret to end
SendMessage(GetDlgItem(m_hWnd,IDT_OUTPUT), EM_REPLACESEL, 0, (LPARAM)buffer); // append text
SendMessage(GetDlgItem(m_hWnd,IDT_OUTPUT), EM_SCROLLCARET, 0, 0); // scroll to caret
}
shutdown(lhSocket, 0x02); // 0x02 = SD_BOTH
closesocket(lhSocket);
}

// shutdown(lhSocket, 0x02); // 0x02 = SD_BOTH
  CloseHandle((void *)lhSocket);
  WSACleanup();  //=== Tell WinSock it's Time to Pick-up it's Toys and Go Home.
return TRUE;
}

Note: the top function (isSocWritable()) is entirely mine, the bottom function (has been modified to include the relevant problem child code) is from the LinkSixteen port scanner code which came from StromCode.com's Win32 Turtorial part 8. Which I'm using as a test framework (to avoid getting fired for posting propritery code from the actual application in question :))

The production code outputs to a ListView control & has much more error checking (which is excluded for clarity).
« Last Edit: April 26, 2009, 11:28 AM by Stoic Joker »