[Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

for rllibby ( close ports )

Posted on 2004-11-25
8
Medium Priority
?
1,994 Views
Last Modified: 2010-04-05
for mods:

i have seperated out this suggestion from q
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_21194414.html
because it is not a solution for this q, but a very valueable suggestion

for rllibby:

thanks for your time and knowledge.

-------------- the suggestion

http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_21194414.html#12567693


Meikl,

I'm sure that you could have worked the code to fit yuor situation, but I figured I would save you the time. Here is a re-coding of the tcp table handling so its a little more generic, and can be used as a set of function calls. There are only a few functions, so the learning curve is pretty low

function     TcpOpenEnum(var TcpTable: PTcpTable): DWORD;
procedure  TcpCloseEnum(TcpTable: PTcpTable);
function     TcpPortFromLong(Port: LongWord): Word;
function     TcpAddrFromLong(Address: LongWord): String;
function     TcpStateDescription(State: LongWord): String;
function     TcpDeleteRow(TcpRow: PTcpRow): DWORD;

An example of using all functions:

var  lpTable:       PTcpTable;
     dwCount:       Integer;
begin

  // Retrieve the table of tcp entries
  if (TCPOpenEnum(lpTable) = ERROR_SUCCESS) then
  begin
     // Resource protection
     try
        // Walk the table entries
        for dwCount:=0 to Pred(lpTable^.dwNumEntries) do
        begin
           // Write out
           // -  the local port (in common format, vs network order)
           // -  the local address (in string format)
           // -  the descriptive state of the tcp entry
           WriteLn(TcpPortFromLong(lpTable^.Table[dwCount].dwLocalPort),
                   ' , ',
                   TcpAddrFromLong(lpTable^.Table[dwCount].dwLocalAddr),
                   ' , ',
                   TcpStateDescription(lpTable^.Table[dwCount].dwState));

           // Example of closing a tcp port/connection
           // - check for a connection to a remote port 80 (http) and close it
           if (TcpPortFromLong(lpTable^.Table[dwCount].dwRemotePort) = 80) then
              TcpDeleteRow(@lpTable^.Table[dwCount]);
        end;
     finally
        // Free the memory allocated by the open enum function
        TCPCloseEnum(lpTable);
     end;
  end;

end;

And finally, the source for it all.

Let me know if you run into questions/problems,
Russell

--------

unit TcpApi;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit           :  TCPAPI
//   Date           :  Original -  05.25.2004
//                     Updated  -  11.12.2004
//   Author         :  rllibby
//
//   Description    :  Set of TCP enumeration and helper routines.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows,
  SysUtils;

////////////////////////////////////////////////////////////////////////////////
//   General constants
////////////////////////////////////////////////////////////////////////////////
const
  ALLOC_SIZE        =  4096;

////////////////////////////////////////////////////////////////////////////////
//   Data structures
////////////////////////////////////////////////////////////////////////////////
type
  PMIB_TCPROW       =  ^MIB_TCPROW;
  MIB_TCPROW        =  packed record
     dwState:       LongWord;
     dwLocalAddr:   LongWord;
     dwLocalPort:   LongWord;
     dwRemoteAddr:  LongWord;
     dwRemotePort:  LongWord;
  end;
  TTcpRow           =  MIB_TCPROW;
  PTcpRow           =  ^TTcpRow;

  PMIB_TCPTABLE     =  ^MIB_TCPTABLE;
  MIB_TCPTABLE      =  packed record
     dwNumEntries:  LongWord;
     Table:         Array [0..MaxWord] of MIB_TCPROW;
  end;
  TTcpTable         =  MIB_TCPTABLE;
  PTcpTable         =  ^TTcpTable;

  PIP_BYTES         =  ^IP_BYTES;
  IP_BYTES          =  Array [0..3] of Byte;
  TIpBytes          =  IP_BYTES;
  PIpBytes          =  ^TIpBytes;

////////////////////////////////////////////////////////////////////////////////
//   Function definitions
////////////////////////////////////////////////////////////////////////////////
type
  TGetTcpTable      =  function(lpTcpTable: PTcpTable; lpdwSize: PDWORD; bOrder: BOOL): DWORD; stdcall;
  TSetTcpEntry      =  function(lpTcpRow: PTcpRow): DWORD; stdcall;

////////////////////////////////////////////////////////////////////////////////
//   TCP table entry state constants
////////////////////////////////////////////////////////////////////////////////
const
  MIB_TCP_STATE_CLOSED       =  1;
  MIB_TCP_STATE_LISTEN       =  2;
  MIB_TCP_STATE_SYN_SENT     =  3;
  MIB_TCP_STATE_SYN_RCVD     =  4;
  MIB_TCP_STATE_ESTAB        =  5;
  MIB_TCP_STATE_FIN_WAIT1    =  6;
  MIB_TCP_STATE_FIN_WAIT2    =  7;
  MIB_TCP_STATE_CLOSE_WAIT   =  8;
  MIB_TCP_STATE_CLOSING      =  9;
  MIB_TCP_STATE_LAST_ACK     =  10;
  MIB_TCP_STATE_TIME_WAIT    =  11;
  MIB_TCP_STATE_DELETE_TCB   =  12;

const
  MIB_TCP_STATES:            Array [0..12] of PChar =
                            ('Unknown',
                             'Closed',
                             'Listening',
                             'Syn Sent',
                             'Syn Received',
                             'Established',
                             'Fin Wait1',
                             'Fin Wait2',
                             'Close Wait',
                             'Closing',
                             'Last Ack',
                             'Time Wait',
                             'Deleted');

////////////////////////////////////////////////////////////////////////////////
//   Late bound function wrappers
////////////////////////////////////////////////////////////////////////////////
function   GetTcpTable(lpTcpTable: PTcpTable; lpdwSize: PDWORD; bOrder: BOOL): DWORD; stdcall;
function   SetTcpEntry(lpTcpRow: PTcpRow): DWORD; stdcall;

////////////////////////////////////////////////////////////////////////////////
//   TCP functions designed to be used by developers
////////////////////////////////////////////////////////////////////////////////
function   TcpOpenEnum(var TcpTable: PTcpTable): DWORD;
procedure  TcpCloseEnum(TcpTable: PTcpTable);
function   TcpPortFromLong(Port: LongWord): Word;
function   TcpAddrFromLong(Address: LongWord): String;
function   TcpStateDescription(State: LongWord): String;
function   TcpDeleteRow(TcpRow: PTcpRow): DWORD;

implementation

////////////////////////////////////////////////////////////////////////////////
//   Library and function name constants
////////////////////////////////////////////////////////////////////////////////
const
  LIB_IPHLPAPI            =  'iphlpapi.dll';
  FUNC_GETTCPTABLE        =  'GetTcpTable';
  FUNC_SETTCPENTRY_NAME   =  'SetTcpEntry';

////////////////////////////////////////////////////////////////////////////////
//   Protected variables
////////////////////////////////////////////////////////////////////////////////
var
  hIphlp:           HMODULE        =  0;
  _GetTcpTable:     TGetTcpTable   =  nil;
  _SetTcpEntry:     TSetTcpEntry   =  nil;

function TcpDeleteRow(TcpRow: PTcpRow): DWORD;
begin

  // Check assignment
  if Assigned(TcpRow) then
  begin
     // Set entry state
     TcpRow^.dwState:=MIB_TCP_STATE_DELETE_TCB;
     // Call SetTcpEntry
     result:=SetTcpEntry(TcpRow);
  end
  else
     // Invalid param
     result:=ERROR_INVALID_PARAMETER;

end;

function TcpStateDescription(State: LongWord): String;
begin

  // Handle state
  if State in [MIB_TCP_STATE_CLOSED..MIB_TCP_STATE_DELETE_TCB] then
     // Return state description
     result:=MIB_TCP_STATES[State]
  else
     // Unknown state
     result:=MIB_TCP_STATES[0];

end;

function TcpAddrFromLong(Address: LongWord): String;
var  lpBytes:    TIpBytes;
     dwIndex:    Integer;
begin

  // Move dword to byte array
  Move(Address, lpBytes, SizeOf(LongWord));

  // Set start of string
  result:=IntToStr(lpBytes[0]);

  // Walk remaining bytes
  for dwIndex:=Succ(Low(lpBytes)) to High(lpBytes) do result:=result+'.'+IntToStr(lpBytes[dwIndex]);

end;

function TcpPortFromLong(Port: LongWord): Word;
begin

  // Convert from network order to common port format
  result:=(Port div 256) + (Port mod 256) * 256;

end;

function TcpOpenEnum(var TcpTable: PTcpTable): DWORD;
var  dwSize:        DWORD;
begin

  // Set the default size, this is enough to hold appx 204 entries
  dwSize:=ALLOC_SIZE;

  // Allocate memory
  TcpTable:=AllocMem(dwSize);

  // Attempt to get the full tcp table
  result:=GetTcpTable(TcpTable, @dwSize, True);

  // Check for insuffecient buffer
  if (result = ERROR_INSUFFICIENT_BUFFER) then
  begin
     // Re-alloc the table
     ReAllocMem(TcpTable, dwSize);
     // Call the function again
     result:=GetTcpTable(TcpTable, @dwSize, True);
  end;

  // Check result
  if (result <> ERROR_SUCCESS) then
  begin
     // Failed to get table, cleanup allocated memory
     FreeMem(TcpTable);
     // Clear the table
     TcpTable:=nil;
  end;

end;

procedure TcpCloseEnum(TcpTable: PTcpTable);
begin

  // Need to free the memory allocated by a call to open enum
  if Assigned(TcpTable) then FreeMem(TcpTable);

end;

function GetTcpTable(lpTcpTable: PTcpTable; lpdwSize: PDWORD; bOrder: BOOL): DWORD;
begin

  // Make sure the api function was bound
  if Assigned(@_GetTcpTable) then
     // Call the function
     result:=_GetTcpTable(lpTcpTable, lpdwSize, bOrder)
  else
     // Function was not bound
     result:=ERROR_PROC_NOT_FOUND;

end;

function SetTcpEntry(lpTcpRow: PTcpRow): DWORD;
begin

  // Make sure the api function was bound
  if Assigned(@_SetTcpEntry) then
     // Call the function
     result:=_SetTcpEntry(lpTcpRow)
  else
     // Function was not bound
     result:=ERROR_PROC_NOT_FOUND;

end;

initialization

  // Load the ip helper api library
  hIphlp:=LoadLibrary(LIB_IPHLPAPI);

  // Attempt to get the function addresses
  if (hIphlp > 0) then
  begin
     // Bind both the get table and set entry functions
     @_GetTcpTable:=GetProcAddress(hIpHlp, FUNC_GETTCPTABLE);
     @_SetTcpEntry:=GetProcAddress(hIpHlp, FUNC_SETTCPENTRY_NAME);
  end;

finalization

  // Clear bound functions
  @_GetTcpTable:=nil;
  @_SetTcpEntry:=nil;

  // Free the ip helper api library
  if (hIphlp > 0) then FreeLibrary(hIphlp);

end.

--------------------------------------

many thanks

meikl ;-)
0
Comment
Question by:kretzschmar
  • 4
  • 3
8 Comments
 
LVL 4

Expert Comment

by:tobjectpascal
ID: 12673758
Very interesting code, i tried it, all it does is disconnect the socket/connection i am right in thinking that's all it does, you can't close off a port completely or get proccess id of the application that's connected or is there more to it somewhere else?
0
 
LVL 27

Author Comment

by:kretzschmar
ID: 12674299
yep, usual it was thought to close a port
(my question header is not correct)

maybe rllibby can tell more

meikl ;-)

0
 
LVL 27

Author Comment

by:kretzschmar
ID: 12674307
question title corrected from block into close ;-))
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 26

Accepted Solution

by:
Russell Libby earned 2000 total points
ID: 12696756
Thanks for the points Meikl. I would have posted sooner but its the holiday season here, and I took a few days off....

Regarding the code; yes it closes ports, no it does not block a port.  In order to truly block a port / address, working with the lower layer of the tcp stack is required. Fortunately, this is made a little simpler through the use of the ip helper API's, which have been around since Win98. The downside though is the lack of documentation / examples for this api usage. Some code examples that I worked on for port/address blocking can be found here though:

http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20829690.html

While the code does need some cleanup, it provides the basics for blocking.

Regards,
Russell
0
 
LVL 4

Expert Comment

by:tobjectpascal
ID: 12697404
0
 
LVL 27

Author Comment

by:kretzschmar
ID: 12697679
thanks for your time, russell
0
 
LVL 4

Expert Comment

by:tobjectpascal
ID: 12697710
program netblock;
{$APPTYPE CONSOLE}

uses
  Windows,
  GetIP,
  SysUtils,
  fltdefs,
  winsock;

// IP address as an array of 4 bytes
type
  PIpBytes       =  ^TIpBytes;
  TIpBytes       =  Array [0..3] of Byte;

// Enumerations
type
  TIpInOut       =  (ioIn, ioOut);
  TIpProtocol    =  (protoTcp, protoUdp, protoAny);

// Globals
var
  hIF:           INTERFACE_HANDLE;
  ipLocal:       TIpBytes;

// Convert string to ip

Function StrToIpBytes(IpStr: String): TipBytes;
Var
 N: Integer;
Begin
 N:=0;
 While Pos('.',IpStr)>0 Do
  Begin
    Result[N]:=StrToInt(Copy(IpStr,1,Pos('.',IpStr)-1));
    Delete(IpStr,1,Pos('.',IpStr));
    Inc(N);
  End;
End;

function StrToIp(lpszIP: PChar; lpipAddr: PIpBytes): PIpBytes;
var  lpszStr:    Array [0..63] of Char;
     dwPos:      Integer;
     lpPos:      PChar;
begin

  // Copy the IP string over
  StrLCopy(@lpszStr, lpszIP, SizeOf(lpszStr));
  lpszStr[Pred(SizeOf(lpszStr))]:=#0;

  // Clear output buffer
  ZeroMemory(lpipAddr, SizeOf(TIpBytes));

  // Parse into bytes
  dwPos:=Pred(SizeOf(TIpBytes));
  lpPos:=StrRScan(lpszStr, '.');
  while Assigned(lpPos) do
  begin
     lpPos^:=#0;
     Inc(lpPos);
     lpipAddr^[dwPos]:=StrToIntDef(lpPos, 0);
     Dec(dwPos);
     if (dwPos = 0) then break;
     lpPos:=StrRScan(lpszStr, '.');
  end;
  lpipAddr^[dwPos]:=StrToIntDef(lpszStr, 0);

  // Result is the pointer to buffer
  result:=lpipAddr;

end;

// Get the local ip address
function GetLocalIPAddr(lpipAddr: PIpBytes): Boolean;
var  lpszLocal:  Array [0..255] of Char;
     pheAddr:    PHostEnt;
begin

  // Get the host name
  if (gethostname(lpszLocal, SizeOf(lpszLocal)) = 0) then
  begin
     // Get the host ent structure
     pheAddr:=gethostbyname(lpszLocal);
     if Assigned(pheAddr) then
     begin
        // Get the ip address
        Move(pheAddr^.h_addr_list^^, lpipAddr^, 4);
        result:=True;
     end
     else
        result:=False;
  end
  else
     result:=False;

end;

// Add a filter
procedure AddFilter(ioType: TIpInOut; lpszRemote: PChar; protoType: TIpProtocol; lpszPort: PChar);
var  ipFlt:      PF_FILTER_DESCRIPTOR;
     dwPort:     Integer;
     ipDest:     TIpBytes;
     ipSrcMask:  TIpBytes;
     ipDstMask:  TIpBytes;
     dwRet:      DWORD;
begin

  // Clear the filter description buffer
  ZeroMemory(@ipFlt, SizeOf(ipFlt));

  // Set the static filtering flags
  ipFlt.dwFilterFlags:=FD_FLAGS_NOSYN;
  ipFlt.dwRule:=0;
  ipFlt.pfatType:=PF_IPV4;
  ipFlt.fLateBound:=0;

  // Set protocol filtering
  case protoType of
     protoTcp :  ipFlt.dwProtocol:=FILTER_PROTO_TCP;
     protoUdp :  ipFlt.dwProtocol:=FILTER_PROTO_UDP;
  else
     ipFlt.dwProtocol:=FILTER_PROTO_ANY;
  end;

  // If nil is passed for the port, set port type to any
  if Assigned(lpszPort) then
     dwPort:=StrToIntDef(lpszPort, FILTER_TCPUDP_PORT_ANY)
  else
     dwPort:=FILTER_TCPUDP_PORT_ANY;

  // Set port ranges
  case ioType of
     // Filter all inbound connections to specified port
     ioIn  :
     begin
        ipFlt.wDstPort:=FILTER_TCPUDP_PORT_ANY;
        ipFlt.wDstPortHighRange:=FILTER_TCPUDP_PORT_ANY;
        ipFlt.wSrcPort:=dwPort;
        ipFlt.wSrcPortHighRange:=dwPort;
     end;
     // Filter all outbound connections to specific port
     ioOut :
     begin
        ipFlt.wDstPort:=dwPort;
        ipFlt.wDstPortHighRange:=dwPort;
        ipFlt.wSrcPort:=FILTER_TCPUDP_PORT_ANY;
        ipFlt.wSrcPortHighRange:=FILTER_TCPUDP_PORT_ANY;
     end;
  end;

  // Create default subnet masks
  StrToIP('255.255.255.255', @ipSrcMask);
  StrToIP('255.255.255.255', @ipDstMask);

  // Check for input or output filter
  if (ioType = ioIn) then
  begin
     // Input filter
     if Assigned(lpszRemote) then
     begin
        ipFlt.SrcAddr:=PByteArray(StrToIp(lpszRemote, @ipDest));
        ipFlt.SrcMask:=@ipSrcMask;
     end
     else
     begin
        ipFlt.SrcAddr:=PByteArray(StrToIp('0.0.0.0', @ipDest));
        StrToIP('0.0.0.0', @ipSrcMask);
        ipFlt.SrcMask:=@ipSrcMask;
     end;
     ipFlt.DstAddr:=@ipLocal;
     ipFlt.DstMask:=@ipDstMask;
     PfAddFiltersToInterface(hIF, 1, @ipFlt, 0, nil, nil);
  end
  else
  begin
     // Output filter
     ipFlt.SrcAddr:=@ipLocal;
     ipFlt.SrcMask:=@ipSrcMask;
     if Assigned(lpszRemote) then
     begin
        ipFlt.DstAddr:=PByteArray(StrToIp(lpszRemote, @ipDest));
        ipFlt.DstMask:=@ipDstMask;
     end
     else
     begin
        ipFlt.DstAddr:=PByteArray(StrToIp('0.0.0.0', @ipDest));
        StrToIP('0.0.0.0', @ipDstMask);
        ipFlt.DstMask:=@ipDstMask;
     end;
     PfAddFiltersToInterface(hIF, 0, nil, 1, @ipFlt, nil);
  end;

end;


////////////////////////////////////////////////////////////////////////////////
// WinMain
////////////////////////////////////////////////////////////////////////////////
var
  wsaData:       TWSAData;
  MIP: String;
begin

  // Initialize winsock so we can get the local ip address
  if (WSAStartup(MakeWord(1, 1), wsaData) = 0) then
  begin

     // Get the local IP address (Network or Assigned ISP IP should it get? as it gets network)
     //192.168.0.1
     MIP:=GetIPAddress; //Get the real IP
     FillChar(IpLocal,4,#0);
     IpLocal:=StrToIpBytes(MIP); //convert it to the byte array
     If MIP<>'' Then
     begin
       // Create the interface
        PfCreateInterface(0, PF_ACTION_FORWARD, PF_ACTION_FORWARD, False, True, hIF);

        // Add some filters - these are just examples
        AddFilter(ioIn, '66.102.7.104', protoTcp, nil);
        AddFilter(ioOut, '66.102.7.104', protoTcp, '80');
        AddFilter(ioOut, '216.239.53.99', protoTcp, '80');
        AddFilter(ioIn, '66.218.70.48', protoUdp, '1024');

        // Example of blocking all outbound to web sites
        AddFilter(ioOut, nil, protoTcp, '80');

       //not working at all
        AddFilter(ioOut, '203.217.3.209', protoTcp, '80');
        AddFilter(ioOut,  Nil, protoTcp, '80');
       //..

        // Bind the interface to the local IP address
        PfBindInterfaceToIPAddress(hIF, PF_IPV4, @ipLocal);

        // Wait until enter is pressed
        WriteLn('Press [ENTER] to stop filtering');
        ReadLn;

        // Unbind and remove filter interface
        PfUnBindInterface(hIF);
        PfDeleteInterface(hIF);

     end
     else
        // Display the winsock error
        WriteLn(Format('WinSock error: %d', [WSAGetLastError]));

     // Cleanup
     WSACleanup;

  end
  else
     // Display the winsock error
     WriteLn(Format('WinSock error: %d', [WSAGetLastError]));

end.


Well that will do me fine, but feel free to make the modifications and take the points :)

0
 
LVL 4

Expert Comment

by:tobjectpascal
ID: 12697740
eek

Function StrToIpBytes(IpStr: String): TipBytes;
Var
 N: Integer;
Begin
 N:=0;
 While Pos('.',IpStr)>0 Do
  Begin
    Result[N]:=StrToInt(Copy(IpStr,1,Pos('.',IpStr)-1));
    Delete(IpStr,1,Pos('.',IpStr));
    Inc(N);
  End;
 Result[N]:=StrToInt(IpStr);
End;


I was not finishing off the routine :D that will fix it
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
With just a little bit of  SQL and VBA, many doors open to cool things like synchronize a list box to display data relevant to other information on a form.  If you have never written code or looked at an SQL statement before, no problem! ...  give i…
Suggested Courses

864 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question