TCP Port Scanning

This is code for tcp port scanning.

for Windows

/*
 portscan.c

 how to cpmpile
 % gcc -I$(TCL)/include -DUSE_TCL_STUBS -c portscan.c
 % gcc -shared -o win32/portscan.dll portscan.o -L$(TCL)/lib -ltcl85 -ltclstub85 -lws2_32 -liphlpapi
*/

#include <tcl.h>
#include <tk.h>

#ifdef __MINGW32__
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#endif

#include <stdio.h>

#ifdef __MINGW32__
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
static int portscan_HandleProc(
    ClientData data, Tcl_Interp *interp, 
    int objc, Tcl_Obj *CONST objv[])
{
        // Declare and initialize variables
        PMIB_TCPTABLE pTcpTable;
        DWORD dwSize = 0;
        DWORD dwRetVal = 0;

        char szLocalAddr[128];
        char szRemoteAddr[128];

        struct in_addr IpAddr;

        int i;

        pTcpTable = (MIB_TCPTABLE *) MALLOC(sizeof (MIB_TCPTABLE));
        if (pTcpTable == NULL) {
                //printf("Error allocating memory\n");
                return TCL_ERROR;
        }

        dwSize = sizeof (MIB_TCPTABLE);
        if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)) ==
                ERROR_INSUFFICIENT_BUFFER) {
                FREE(pTcpTable);
                pTcpTable = (MIB_TCPTABLE *) MALLOC(dwSize);
                if (pTcpTable == NULL) {
                        //printf("Error allocating memory\n");
                        return TCL_ERROR;
                }
        }
        if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)) == NO_ERROR) {
                for (i = 0; i < (int) pTcpTable->dwNumEntries; i++) {
                        IpAddr.S_un.S_addr = (u_long) pTcpTable->table[i].dwLocalAddr;
                        strcpy(szLocalAddr, inet_ntoa(IpAddr));
                        IpAddr.S_un.S_addr = (u_long) pTcpTable->table[i].dwRemoteAddr;
                        strcpy(szRemoteAddr, inet_ntoa(IpAddr));

                        Tcl_AppendResult(interp, "{", NULL);

                        switch (pTcpTable->table[i].dwState) {
                        case MIB_TCP_STATE_CLOSED:
                                Tcl_AppendResult(interp, "CLOSED ", NULL);
                                break;
                        case MIB_TCP_STATE_LISTEN:
                                Tcl_AppendResult(interp, "LISTEN ", NULL);
                                break;
                        case MIB_TCP_STATE_SYN_SENT:
                                Tcl_AppendResult(interp, "SYN-SENT ", NULL);
                                break;
                        case MIB_TCP_STATE_SYN_RCVD:
                                Tcl_AppendResult(interp, "SYN-RECEIVED ", NULL);
                                break;
                        case MIB_TCP_STATE_ESTAB:
                                Tcl_AppendResult(interp, "ESTABLISHED ", NULL);
                                break;
                        case MIB_TCP_STATE_FIN_WAIT1:
                                Tcl_AppendResult(interp, "FIN-WAIT-1 ", NULL);
                                break;
                        case MIB_TCP_STATE_FIN_WAIT2:
                                Tcl_AppendResult(interp, "FIN-WAIT-2 ", NULL);
                                break;
                        case MIB_TCP_STATE_CLOSE_WAIT:
                                Tcl_AppendResult(interp, "CLOSE-WAIT ", NULL);
                                break;
                        case MIB_TCP_STATE_CLOSING:
                                Tcl_AppendResult(interp, "CLOSING ", NULL);
                                break;
                        case MIB_TCP_STATE_LAST_ACK:
                                Tcl_AppendResult(interp, "LAST-ACK ", NULL);
                                break;
                        case MIB_TCP_STATE_TIME_WAIT:
                                Tcl_AppendResult(interp, "TIME-WAIT ", NULL);
                                break;
                        case MIB_TCP_STATE_DELETE_TCB:
                                Tcl_AppendResult(interp, "DELETE-TCB ", NULL);
                                break;
                        default:
                                Tcl_AppendResult(interp, "UNKNOWN ", NULL);
                                break;
                        }

                        char localPort[1024];
                        sprintf(localPort, "%d", ntohs((u_short)pTcpTable->table[i].dwLocalPort));
                        char remotePort[1024];
                        sprintf(remotePort, "%d", ntohs((u_short)pTcpTable->table[i].dwRemotePort));
                        Tcl_AppendResult(interp, szLocalAddr, " ", 
                                        localPort, " ", szRemoteAddr, " ", remotePort, "} ", NULL);
                }
        } else {
                //printf("\tGetTcpTable failed with %d\n", dwRetVal);
                FREE(pTcpTable);
                return TCL_ERROR;
        }

        if (pTcpTable != NULL) {
                FREE(pTcpTable);
                pTcpTable = NULL;
        }    

    return TCL_OK;
}
#endif

DLLEXPORT int Portscan_Init ( Tcl_Interp* interp )
{
    Tcl_InitStubs(interp, "8.4", 0);
        Tcl_CreateObjCommand(interp, "portscan", portscan_HandleProc, NULL, NULL);
    return Tcl_PkgProvide(interp, "portscan", "1.0");
}

for Linux

proc make_ipv4 {add} {
        set ipv4_0 [format "%d" 0x[string range $add 6 7]]
        set ipv4_1 [format "%d" 0x[string range $add 4 5]]
        set ipv4_2 [format "%d" 0x[string range $add 2 3]]
        set ipv4_3 [format "%d" 0x[string range $add 0 1]]
        set ipv4 "$ipv4_0.$ipv4_1.$ipv4_2.$ipv4_3"
        return $ipv4
}

proc make_port {port} {
        return [format "%d" 0x$port]
}

proc make_status {st} {
        set st [format "%d" 0x$st]
        if { $st == 1 } {
                return "ESTABLISHED"
        } elseif { $st == 2 } {
                return "SYN-SENT"
        } elseif { $st == 3 } {
                return "SYN-REC3EIVED"
        } elseif { $st == 4 } {
                return "FIN-WAIT-1"
        } elseif { $st == 5 } {
                return "FIN-WAIT-2"
        } elseif { $st == 6 } {
                return "TIME-WAIT"
        } elseif { $st == 7 } {
                return "CLOSED"
        } elseif { $st == 8 } {
                return "CLOSE-WAIT"
        } elseif { $st == 9 } {
                return "LAST-ACK"
        } elseif { $st == 10 } {
                return "LISTEN"
        } elseif { $st == 11 } {
                return "CLOSING"
        } else {
                return "UNKNOWN"
        }
}

proc portscan {args} {
        set result [list]

        set fd [open /proc/net/tcp]
        while {![eof $fd]} {
                set line [string trim [gets $fd]]
                if { $line == "" } break

                set portinfo [split $line]
                if { [lindex $portinfo 0] == "sl" } continue

                set localadd [make_ipv4 [lindex [split [lindex $line 1] :] 0]]
                set localport [make_port [lindex [split [lindex $line 1] :] 1]]
                set remoteadd [make_ipv4 [lindex [split [lindex $line 2] :] 0]]
                set remoteport [make_port [lindex [split [lindex $line 2] :] 1]]
                set remoteport [make_port [lindex [split [lindex $line 2] :] 1]]
                set status [make_status [split [lindex $line 3] :]]

                lappend result [list $status $localadd $localport $remoteadd $remoteport]
        }

        close $fd

        return $result
}

Result

% portscan
{LISTEN 0.0.0.0 135 0.0.0.0 2272} {LISTEN 0.0.0.0 445 0.0.0.0 14580} ... {LISTEN 192.168.56.1 139 0.0.0.0 2224}