Link to home
Start Free TrialLog in
Avatar of aikimark
aikimarkFlag for United States of America

asked on

packet filter API example wanted

I'm looking for a Delphi code example of calls to the packet filtering APIs available in Win2000 and WinXP.  Microsoft has published C++ examples, but I haven't found a comparable Delphi example anywhere, including project JEDI.
Avatar of Ferruccio Accalai
Ferruccio Accalai
Flag of Italy image

well look thi delphi example to monitor IP local traffic (Packets In & Out) usin iphlpapi.dll
http://developer.novell.com/support/sample/tids/dmonip/dmonip.htm
Avatar of GloomyFriar
GloomyFriar

If you have C++ samples I think It's rather easy to translate them to Delphi.
Avatar of aikimark

ASKER

Ferruccio68,

There is no packet-filtering Delphi example in your links, just packet monitoring.

================================
GloomyFriar,

We can come close with the iphlpapi translation work done by the JEDI project.  However, they don't have a packet-filtering example.
OK...i think that it's difficult to find a packet filtering source code for delphi...
BTW this link point to a free activex compatible with delphi 3-4-5 too...(documentation included)...it's a trial version...
http://www.datawizard.net/Free_Software/SocketView_Free/socketview_free.htm

another interesting link is this: http://users.pandora.be/dirk.claessens2/
a free source code in it (delphi packet sniffer) with packet filtering option....

Ferruccio68,

I agree with you that this is a difficult question I am asking.  That is why I assigned it 500 points and have added an additional 250 points in another (referencing) question.  I have spent a LOT of time searching the WWWeb for this.  With no search results, I turned to the EE Delphi experts for a possible answer.  If I need to award more points to get the answer I seek, I am willing to do that.

Thank you for your search results.  If I can find a Delphi code example of performing packet filtering using the packet-filtering calls encapsulated in IPHLPAPI.DLL, then I won't have to use a third-party interface to hook the IP stack.  The SocketView component isn't exactly free (~$600) and has run-time licensing fees.

The dirk.claessens2 link has filtering of packets that are 'sniffed'.  It does not provide a firewall-like filtering of IP packets.
ASKER CERTIFIED SOLUTION
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Russell,

Thank you.  I'm going to verify this over the weekend.  I'll let you know if I have any questions or problems with this.  In the mean time, please add a comment to an associated question
(https://www.experts-exchange.com/questions/20834905/Addnl-pts-for-question-total-750.html)
so I can award you the entire 750 points.
Russell,

Thank you.  This works.  I am considering sharing this API translation with Project JEDI.  Do you have any objections?

Don't forget about the extra-points question.

No objections from me, as its nothing more than a delphi version of the C header file (plus the weird function names that I had to dig out of the dll ;-) . And I did post a comment in the other q as well.

Thanks and best regards,
Russell
Russell,

Nice job, the only thing I've noticed is that nil for All addresses is not working,
 // Example of blocking all outbound to web sites
    AddFilter(ioOut, nil, protoTcp, '80');

Can you please check it out and tell me how can I specify destaddr to be ALL .

Thanks.


Perhaps you can be more specific than "not working". The above filter code:

AddFilter(ioOut, nil, protoTcp, '80');

should deny - outbound access / using tcp only / to destination port 80 only / to any remote host.

If the web site is actually on another port (like 81), then it will not be filtered. For the address(es) that it is not working on, have you performed a "netstat" command to verify that the actual destination port truly is 80? If so, then perhaps you could list the remote address here so I can verify.

Regards,
Russell



Sorry, I'll be more specific.
I have two computers at home and both have web servers, netbios, shared folders, etc.
Session (port) is not in case here, same situation is with any port both ioIn and ioOut.
Problem is with ipFlt.DstAddr:=nil;
So, Comp1 IP address is 10.16.16.10 and Comp2 have 10.16.16.150.
When i try  from Comp1

AddFilter(ioOut, '10.16.16.150', protoTcp, '80');

it works just fine (I see no web page),
but when I replace above line with

AddFilter(ioOut, nil, protoTcp, '80');

I CAN SEE web page !

Same thing is on Internet as well, for example IP address of https://www.experts-exchange.com
is 64.156.132.140 , so when i put

AddFilter(ioOut, '64.156.132.140', protoTcp, '80');

https://www.experts-exchange.com is not opening, but when i replace IP string with nil , guess what :)
Try it ! Port for this site is http(80), please try any other site, most are http, same result.
Anyway, if port 81 may be the reason, try nil for port as well (btw, nil for ports is working)

All I'm saying is that everything works just fine with packet filtering when you
specify IP address, but when you want to apply that rule for any remote host,
packet is going through. Trust me, I've tried many scenarios.


I'll take a look at in the am...
You should be aware though, that I still hold by my original post:

<quoting myself>

I am also including a small console application that demonstrates packet filtering (either inbound or outbound), though I take no credit for the code. The code is based off from a small service app written in C by Ton Plooy.

<end quote>

Hopefully I can find the problem, but if not, you will have to take over with what is already there.

Russell

Alright, the problem was in the source examples (I only had 2 to base the code from, one mentioned above, and another on the Code Project site written in C#) I used for the filtering. This is not documented in the MSDN, or anywhere else as far as I can tell...

It turns out that you cannot specify nil for any of the src/dest addresses or masks, as the api will return an error 87, which is defined as "incorrect parameter". I am posting the solution for this here, and suggest that a better solution would be to wrap the filtering in a class object to allow for:

1.) specific ip range filtering
2.) tracking of the installed filter handle
3.) encapsulation of adding and removing a specific filter
4.) greater control and flexibility

I am not proposing that I am going to do this either, though, as this is a closed question. If you need further assistance in regards to filtering, then please post in a new question.

Regards,
Russell

---- Correction for handling nil (all) address ----
 
// 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;



It's working now, thank you.


Hi Russell,

The code is perfect.
but I couldn't test it for ICMP protocol.

you didn't implement the ICMP protocol.
there is a constant for it in the fltdefs.h and your code.
do you have any idea how we can add ICMP to the code?
I tried to use FILTER_PROTO_ICMP for dwProtocol, but it seems it doesn't work properly.

for example by using AddFilter(ioIn, nil, protoIcmp, '7');
we can block the ping command.

thank you in advanced,
adli

adli,

In all fairness to both myself and the original asker (who posted points for this question/answer), I would like to suggest that you open a new question in the Delphi TA regarding the ICMP handling. This question as it was asked is closed, and I only have a limited amount of time to work on researching this for you. A new question will get the attention of others in the Delphi TA who are probably just as suited to answer this question, as this really comes down to researching/testing the ICMP handling (not much source out there for me to give you a quick and definitive answer)

Regards,
Russell