C++/Win32: Port Scanning and Sockets
March 2, 2008
At this point, all the framework for this project is done. All that’s left is to actually make it do something. The first half of that is receiving the input from the user, and then checking it to make sure it’s valid. If it is, we’ll pass this info along to a function that actually does the scanning and outputs its results to our text box. If the data is invalid, for any number of reasons, we will pop up a message box saying so, and return to our idle state to wait for another button press.
So first, as I mentioned before, we’ll want to wrap the process of receiving text from an edit control into a member function of the PortScannerWindow class. We need to declare it in PortScannerWindow.h, and define it in PortScannerWindow.cpp. Remember that the actual Windows function that does this is GetDlgItemText, and it stores the text string into a buffer. We will need the HWND of the parent window, and the resource ID of the edit we’re reading from. Basically, we’ll need everything that GetDlgItemText needs, because we’ll be handing all that data off half way through the function. But we can be efficient and leave out the HWND, since it will always be m_hWnd. We also
don’t need len, because the function’s job is to handle that. And instead of passing in a char *, we will have our function return a pointer to the string we’ve bulit in the function.
Here’s the function declaration:
char* GrabTextFromEdit(int nResourceID);
That should certainly look easier to use than what we saw before. Just pass in the resource ID, and we get back a pointer to a string.
Here’s the function definition:
char* PortScannerWindow::GrabTextFromEdit(int nResourceID) {
int len = GetWindowTextLength(GetDlgItem(m_hWnd, nResourceID));
if (len > 0) {
int i;
char *buffer;
buffer = (char*)GlobalAlloc(GPTR, len + 1);
GetDlgItemText(m_hWnd, nResourceID, buffer, len + 1);
return buffer;
}
}
PIECE OF CAKE. The only thing is, we’ll have to remember to de-allocate our char * when we’re done with it, using GlobalFree.
Now that we have that function done, we can write another function that will be called by our message handler whenever it receives a button hit on our Scan button. This new function will make several calls to GrabTextFromEdit to get all the values we need from our edit controls (three, to be exact) and then analyze the data. If it looks ok, this function will return true, signalling us to then call yet another function to do the actual scanning, passing over the IP address, start port, and end port values. If the data is invalid, it will pop up a message box to that effect, and then return false, signaling us NOT to call the scan function. We can also optionally clear out the data fields in the edit controls, but that would probably upset the user, so we’ll just leave it as is.
Here’s the declaration for the validateInput function:
BOOL validateInput();
Notice it doesn’t take any arguments, it just checks out all the resources we’ve got, and returns TRUE if good, FALSE if not.
Here’s the definition:
BOOL PortScannerWindow::validateInput() {
// validate IP address here (not implemented yet)
BOOL bSuccess;
if (GetDlgItemInt(m_hWnd, IDE_STARTPORT, &bSuccess, FALSE) >= 1)
if (GetDlgItemInt(m_hWnd, IDE_ENDPORT, &bSuccess, FALSE) >= 1)
if (GetDlgItemInt(m_hWnd, IDE_STARTPORT, &bSuccess, FALSE)
<= GetDlgItemInt(m_hWnd, IDE_ENDPORT, &bSuccess, FALSE))
return TRUE;
// else
MessageBox(m_hWnd, "Invalid Entry,\nPlease re-enter information", "Invalid Data Entered",
MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
Yes, it doesn’t make sure the IP address is valid. That’s a complicated process we’ll go into later. But notice that it does check that the start port and end port are both greater than 0, and that the start port is less than or equal to the end port. We also didn’t use our nifty new GrabTextFromEdit function, but don’t worry, we’ll need it when we break down the IP address input.
So now we can create a function to do the actual work. It will attempt to open a socket connection to IP:PORT for each port from start port to end port. If the connection is successful, it will send a “open” message to our text area. If it fails, it will send a “closed” message. Here’s some pseudocode:
socket = fsockopen(IPAddress,Port,Timeout);
if(socket) {
PrintToTextArea("IP:PORT : open");
fclose($fp);
} else {
PrintToTextArea("IP:PORT : open");
}
flush(socket);
So we’ll write a function called goScan() that will be called if validateInput() returns true. The short, easy way to do this, from inside our message handler, is this:
if (validateInput()) goScan();
There are 5 steps to using sockets:
1. Create a socket and get the handle
2. Populate a SOCKADDR_IN structure with the server IP and port number
3. Connect using the connect function
4. Send and Recv using the socket
5. Shutdown and close when all jobs are done
We aren’t going to be communicating with anything — we’re just seeing if a connection is possible — so we can skip step 4. But think about that for a minute — if you can figure this out, you only need to learn two more functions to know how to write server and client programs. That’s way cool.
This will be the longest function we have so far, naturally, because it is the one that actually does all the work. It looks complicated, but only because of it’s size.
The declaration:
BOOL goScan();
The definition:
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
// 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);
}
// 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);
// Attempt connect
lConnect = connect(lhSocket,(SOCKADDR *)&lSockAddr,sizeof(SOCKADDR_IN));
if(lConnect != 0) {
// On connect failure:
// Grab text from text area, and output result of this scan
sprintf(buffer,"%s:%d - Closed\n",IPAddress,i);
SetDlgItemText(m_hWnd, IDT_OUTPUT, buffer);
} else {
// On connect success:
// Grab text from text area, and output result of this scan
sprintf(buffer,"%s:%d - Open\n",IPAddress,i);
SetDlgItemText(m_hWnd, IDT_OUTPUT, buffer);
}
closesocket(lhSocket);
}
return TRUE;
}
Complicated, but not so bad. In order to use the socket stuff, you need to #include <winsock2.h>, except you really don’t because by including <windows.h> you get <winsock2.h> automatically. So don’t include it, just remember that that’s where the definitions are stored. You will also need to add ws2_32.lib to the list of library files, so the linker won’t freak. To do this, go to the Visual Studio menu, Project->Win32WrapperClass Properties->Linker->Input and add ws2_32.lib to the Additional Dependencies field. Finally, in order to use the sprintf function I used to build the output, you need to include <stdio.h> at the top of PortScannerWindow.cpp.
Hopefully you’ll get this to compile and run. You’ll notice it’s working, but not really the way we’d like. We’d never show this to anyone, in other words. Here’s a few things that suck about it so far:
1. The interface is hideous
2. Standard stuff like tabbing to the next field doesn't work. We'll have to do that by hand.
3. It's slow. Why? Because we have to wait for every attempted socket connection to timeout
before going on to the next one. It would be much better if we could have ten or so of
them going at the same time, and that's where threading comes in.
4. The output is lame. It should show the current result, but still keep all the old results
up there. To do that, we'll have to play around with strings more, and learn how to
attach a scrollbar to a text area.
5. While we are in the goScan loop, we can't do anything. Can't close the window, can't move it,
nothing. This is because as long as we're in the goScan loop, we aren't running the main
message pump loop in WinMain, so we aren't processing messages. The messages are still
there, we just aren't processing them. Try to close the window while it's scanning, and
you'll notice that the window will close as soon as the scan is done. That's because the
WM_QUIT message went into the queue, but the message pump didn't dispatch it to the message
handler until program control was returned to it. Again, threading will fix this.
6. It also doesn't do name resolution. Put in glowdot.com and the thing will just pretend like
it's doing something. It would be nice, when we validate input, if we also tried to resolve.
At any rate, it works. And if you understood this far, you pretty much know everything you need, really, to write some hectic client/server software.
Next: More GUI.
Source Code:
win32tut_part5.zip [741kb zipped]
Additional Information:
· CoderSource.Net - Win32 Socket Client
· CodeProject - A Simple Windows Port Scanner
Further Reading:
· Nitty Gritty Windows Programming with C++ by Henning Hansen.
· Thinking in C++ by Bruce Eckel.




I’ve written a similiar port scanner but in C
How come the link for the code source does not work?