Link to home
Start Free TrialLog in
Avatar of rthriller
rthrillerFlag for France

asked on

blocking internet connections

Hello

I Admin a 30 computers network running windows Xp Pro, The server running windows 2000 server.
All the computers access internet via a router (ip=192.168.0.254)

I'd like to block internet access for certain machines at a period of time without disabling the local network.

How I want to do this:

A server side application showing the list of computers logged in, with a checkbox for each computer, when checked the computer has nomore access to internet but still has othe lan abilities.
I want the result to be immediate or at a max delay for 30 seconds (no rebooting).

A client side application running on all computers and sending state of internet connection and recieving orders from the server side application.

I am using ICS components (overbyte.be) for communication between both applications.

Please do not suggest me to check google, I did not find any solution there.
Please do not suggest me to check msdn, I won't be able to understand neither C, C++ code not win32api specific vocabulary.

For 500 points I want a working delphi 7 code for windows xp and with no dependencies to commercial or unfoundable components.

Thanks
Avatar of Russell Libby
Russell Libby
Flag of United States of America image


Have you taken a look at an old PAQ that I worked on regarding IP filtering. It does allow you to stop IP access to: any ip address, any port, both inbound, or outbound access. The q is located at:

https://www.experts-exchange.com/questions/20829690/packet-filter-API-example-wanted.html

Im not sure if it will do everything you want; but its already coded, easily implemented, and should not take you too much time to test.

Hope this helps,
Russell
Avatar of rthriller

ASKER


OKay, seems too much complicated to work on proto basis and port basis.
I did not yet try to experiment with it, but I was expecting something easier, like changing gateway ip dynamically.

Anyway, gonna check it this weekend

Thanx

It becomes very simple after the base code is in place. For example, to restrict access to ALL webservers running on either port 80 (http) or 443 (https)

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

I can also give you the routines to remove the filters as well. Regarding the gateway changing (swithching, removal); probably not a good idea - as it **may**  end up causing delays FOR ALL tcpip network traffic.

Another option you have (provided its browser based traffic that you wish to limit, and that its IE related) is to set a proxy setting of 127.0.0.0 in the IE settings. This can of course be done programmatically.

It really just depends on what level, and to what extent, you need to block the traffic.

Russell



It is a school, and while studying some pupils go to internet to chat (msn, icq, mirc, hotmail, caramail...) some others go to meeting sites to seek girls (or even porn sites), others go to music and radio sites.

I cannot get the list of sites and ports to block, I just want to block internet access only to those computers, but let them still exchange files locally.

It was a good idea to remove internet cable from the router, but there is teachers computers that need internet access and that are on the same network.

Is the following okay?
AddFilter(ioOut, nil, protoTcp,nil);
AddFilter(ioIn, nil, protoTcp,nil);
AddFilter(ioOut, nil, protoUdp,nil);
AddFilter(ioIn, nil, protoUdp,nil);

Thanks

Make sense now... (thanks)

And yes, the filters you list above are fine, and should block all incoming/outgoing traffic. Very similar to what the firewalls (symantec, zone alarm, etc) do when the internet traffic "lock" is engaged.

Russell




Just two little things may be missing

1/ A RemoveFilter routine to reenable internet.
2/ Do these routines work on normal user accounts (with no special rights or previledges), if so, it is okay, else how can I log and impersonate a admin account, get the required previledges to run those application.

I do not have enough points to ask another question on this subject, so please be generous with me and help me with a last question about how to run an application as admin, like the RunAs Professionel soft. This is a Bonus that I request you, so even if you don't want to help me, you'll get your 500 & A grade.

Finally, Have you written books on Delphi (especially dealing with windows api and administration stuff) ?
If yes, please give me the title(s)
If no, you really should, It takes time to write a book, people (me) need good books, illustrating usefull advanced techniques, I would pay $100 for such a book.

Thanks

1.) As I stated above, I will provide the remove routine, which will most likely be based on the PfRemoveFilterHandles function. It requires a little work, and I wanted to make sure that the filtering mechanism does what you want first.

2.) Yes. These are normal user mode routines, and AFAIK do not require any special privileges to run the packet filtering functions.

If it did (which in my testing shows it does not), then you start dealing with access tokens. For example, calling LogonUser with the user name/password, and then using the token in ImpersonateLoggedOnUser is one technique that is commonly used (though it does require the SE_TCB_NAME privilege). If we are talking about the WinXP home OS, then there are ways to elevate the process'es privileges without impersonation.

For example, I have some utility routines at home that I use to set the memory working set size for all processes. In order to perform this opertation on the services (as well as user mode running apps), then I use the following:

procedure ElevateSecurity;
var  hToken:        THandle;
     lpszSecName:   Array [0..3] of PChar;
     tp:            TOKEN_PRIVILEGES;
     tpPrevious:    TOKEN_PRIVILEGES;
     luid:          TLargeInteger;
     cbUnused:      DWORD;
     cbPrevious:    DWORD;
     dwCount:       Integer;
begin

  // Set security names
  lpszSecName[0]:='SeSecurityPrivilege';
  lpszSecName[1]:='SeIncreaseQuotaPrivilege';
  lpszSecName[2]:='SeTcbPrivilege';
  lpszSecName[3]:='SeDebugPrivilege';

      // Enable our process to super-level rights
  if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
  begin
     // Iterate the security names to elevate
     for dwCount:=Low(lpszSecName) to High(lpszSecName) do
     begin
        cbPrevious:=SizeOf(TOKEN_PRIVILEGES);
        if LookupPrivilegeValue(nil, lpszSecName[dwCount], luid) then
        begin
           tp.PrivilegeCount:=1;
           tp.Privileges[0].Luid:=luid;
           tp.Privileges[0].Attributes:=0;
           if AdjustTokenPrivileges(hToken, False, tp, SizeOf(TOKEN_PRIVILEGES), @tpPrevious, cbPrevious) then
           begin
              tpPrevious.PrivilegeCount:=1;
              tpPrevious.Privileges[0].Luid:=luid;
                  tpPrevious.Privileges[0].Attributes:=0;
              tpPrevious.Privileges[0].Attributes:=tpPrevious.Privileges[0].Attributes or SE_PRIVILEGE_ENABLED;
              if not(AdjustTokenPrivileges(hToken, False, tpPrevious, cbPrevious, nil, cbUnused)) then break;
           end;
        end;
     end;
  end;

end;

After running this, my process is then able to call SetProcessWorkingSetSize on ALL of the running processes on the system.

3.) For running an application with a certain user account, the CreateProcessAsUser is commonly used. This call does require a user token though, so it requires an extra call to (for example) LogonUser to get this handle. If you are dealing with win2000/xp, then an easier way to launch an app with a specific account is through the use of CreateProcessWithLogonW is easier to use, because it accepts clear text user/domain/password information. Hopefully this gives you a few avenues to look at when dealing with user account security.

4.) No, I have not written any books. I leave that for others much better suited than myself.

Anyways, I will take a look at the filtering, and removal of filters on Monday. I will also test this in a LAN environment to make sure that the internet access is closed, without affecting the internal network traffic. Should have the code finished and posted back here on Monday aftenoon, or Tuesday at the latest

Regards,
Russell




About CreateProcessWithLogonW I founf this little procedure, but it does not work
What's wrong about it?

var
   Jycroisamort : function (lpUsername: PAnsiChar; lpDomain: PAnsiChar;
    lpPassword: PAnsiChar; dwLogonFlags: DWORD; lpApplicationName : PAnsiChar;
    lpCommandLine : PAnsiChar; dwCreationFlags : DWord; lpEnvironment : Pointer;
    lpCurrentDirectory : PAnsiChar; const lpStartupInfo : TStartupInfo ;
    var lpProcessInfo : TProcessInformation) : boolean ; stdcall;
   
  procedure WinExecAsUser(FileName: string; username: string; password: string; Visibility: integer);
  var { V1 by Pat Ritchey, V2 by P.Below }
   zAppName          : array[0..512] of char;
   StartupInfo       : TStartupInfo;
   ProcessInfo       : TProcessInformation;
   h                 : thandle;
  begin
    StrPCopy(zAppName, FileName);
    FillChar(StartupInfo, Sizeof(StartupInfo), #0);
    StartupInfo.cb := Sizeof(StartupInfo);
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartupInfo.wShowWindow := Visibility;
    h :=  LoadLibrary(PChar('advapi32.dll'));
    Jycroisamort := GetProcAddress(h,pchar('CreateProcessWithLogonW'));
    Jycroisamort(pchar(username),'.',pchar(password),$1,nil,zappname,$400,nil,nil,StartupInfo,ProcessInfo);
    if GetLastError <> 0 then ShowMessage(SysErrorMessage(GetLastError));
      FreeLibrary(h);
  end;

Thanx
Whats wrong with it? In short; mainly the use of ansi strings when wide strings are required, not closing process handle, not closing the thread handle, etc etc...

Try this instead:
-------------------------------------

unit Unit2;

interface

uses
  Windows,
  SysUtils;

const
  LOGON_WITH_PROFILE         =  DWORD(1);

type
  TCreateProcessWithLogonW   =  function(lpUsername: LPCWSTR;
                                         lpDomain: LPCWSTR;
                                         lpPassword: LPCWSTR;
                                         dwLogonFlags: DWORD;
                                         lpApplicationName: LPCWSTR;
                                         lpCommandLine: LPWSTR;
                                         dwCreationFlags: DWORD;
                                         lpEnvironment: Pointer;
                                         lpCurrentDirectory: LPCWSTR;
                                         const lpStartupInfo: TStartupInfo;
                                         var lpProcessInfo: TProcessInformation): BOOL; stdcall;

procedure WinExecAsUser(FileName: String; Username: String; Password: String; Visibility: Integer);

var
  CreateProcessWithLogonW:   TCreateProcessWithLogonW = nil;

implementation

var
  hAdvapi:       HMODULE;


procedure WinExecAsUser(FileName: String; Username: String; Password: String; Visibility: Integer);
var  lpSI:          TStartupInfo;
     lpPI:          TProcessInformation;
     lpwsCmd:       Array [0..MAX_PATH * 2] of Char;
begin

  // Check function pointer
  if Assigned(@CreateProcessWithLogonW) then
  begin
     // Clear structures
     ZeroMemory(@lpSI, SizeOf(TStartupInfo));
     ZeroMemory(@lpPI, SizeOf(TProcessInformation));
     // Set startup info fields
     lpSI.cb:=Sizeof(TStartupInfo);
     lpSI.dwFlags:=STARTF_USESHOWWINDOW;
     lpSI.wShowWindow:=Visibility;
     // Convert the application to a wide char pointer
     StringToWideChar(FileName, @lpwsCmd, SizeOf(lpwsCmd));
     // Attempt the create process
     if CreateProcessWithLogonW(PWideChar(WideString(Username)), PWideChar(WideString('.')),
                             PWideChar(WideString(Password)), LOGON_WITH_PROFILE,
                             nil, @lpwsCmd, CREATE_NEW_PROCESS_GROUP or CREATE_UNICODE_ENVIRONMENT,
                             nil, nil, lpSI, lpPI) then
     begin
        // Need to close the process and thread handles
        CloseHandle(lpPI.hProcess);
        CloseHandle(lpPI.hThread);
     end;
  end;

end;

initialization

  // Load library
  hAdvapi:=LoadLibrary('advapi32.dll');

  // Attempt to get the procedure address
  if (hAdvapi <> 0) then @CreateProcessWithLogonW:=GetProcAddress(hAdvapi, 'CreateProcessWithLogonW');

finalization

  // Free the library
  if (hAdvapi <> 0) then FreeLibrary(hAdvapi);

end.

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

Lets try not to get too far off track from the original question though, ok? ;-)

Regards,
Russell


Am sorry...
You know, my last points... and you really master system stuff in relation to delphi. I didn't find this in any book!!

Anyway, I stop asking questions, and I wait for the rest of the answer (removefilter and rights&previleges required)

Thank you.

No problem on the question, just wanted to make sure the original question was addressed first..

I did some more testing (lan based environment), and I don't believe the packet filtering is going to work for you. The reason is that it also ends up blocking intranet traffic, as well as internet traffic. The main problem is keeping the IP handling down to a few filters, while at the same time restricting all IP access that is destined outside the internal network.

I also took a look at gateway disabling, and found (no surprise) that if your gateway (to the router) handles both inter/intra traffic, then disabling/changing the gateway will also disable the internal network browsing as well.

Seems to be one of those cases where the above techniques are either to restrictive, or not restrictive enough.

Other possible alternatives:

Create a system hook library, that hooks the winsock functions like send, recv (WSARecv), etc so your application can handle the forwarding of these calls, or not, depending on the desired functionality. If its for non-commercial use, Madshi's hooking routines can be used to accomplish this (You should also be able to google quite a few  examples of code that hooks winsock).

Alternatively, if you know which applications (like IE, MSN messenger, etc) that the kids are using, you could install a WH_CBT windows hook. This would allow you to catch the window creation (HCBT_CREATEWND), get the process ID from the window handle, then using the psapi library get the actual module name. If its one of those programs that you disallow, then you could return a non-zero value and stop the window creation. (Could also display a messagebox indicating that these apps should not be run).

Sorry I am not able to help further.
Russell

ps: If none of these ideas helps with a solution that works for you, then you should probably ask community support to delete the Q, and refund your points.




Okay, I know if you don't help me, no one else will.

Hmmm, tell me...
Is there a way to catch at realtime the ip and port of a tcp (or udp or other) connection (in or out) then check if it is in 192.168.0.* or not. and then decide weither to block it or not? This way, I won't block intranet, and users will have the illusion that there is no internet and they'll stop trying after a moment.

Of course if this solution exists, i'll still require a remove fillter function, or maybe not.... lemme think.... I'll just create another process just for blocking then kill it, or maybe just unbind the interface cause I do not need to remove individual filters but enable full access after the course is finished.

If this solution is a pervesion and does not exist, I'll have to check my network by changing or remove the default gateway to see if this affects local access. If it does not, you may help me by a way to change it programmatically at realtime (or some seconds delay).

I am sure you are still able to help me, I believe in you :-)

Its not that I don't want to help; it's just a case where to do what your asking is very difficult (from a programmatic standpoint). Regardless of the technique opted for, it will require a good deal of coding to achieve the end results.

Regarding your questions...

1.) Is there a way to catch at realtime the ip and port of a tcp (or udp or other) connection (in or out) then check if it is in 192.168.0.* or not. and then decide weither to block it or not? This way, I won't block intranet, and users will have the illusion that there is no internet and they'll stop trying after a moment.

- Yes. The winsock 2 implementation is layered, so **IF** one writes a winsock layered service provided, then the connections can be checked realtime, and optionally blocked. In regards to writing a layered service provider.... I have yet to see anyone do this in delphi, although it is possible once the C header files have been translated over. Needless to say it would require a good deal of work to do it. The problem still remains where the IP address that is going out WILL NOT be 192.169.9.*

Say for example, the student was attempting to reach www.google.com. The DNS lookup for google will return 66.102.7.99, and this is what the outbound connect will use as the destination IP address. At the lower level, this is how the IP packet gets resolved - (I quote from MSDN)

Based on the destination IP address and the route determination process, IP determines the forwarding IP address and interface to be used to forward the packet. IP then hands the IP packet, the forwarding IP address, and the interface to ARP.

If the forwarding IP address is the same as the destination IP address, then ARP performs a direct delivery. In a direct delivery, the MAC address corresponding to the destination IP address must be resolved.

If the forwarding IP address is not the same as the destination IP address, then ARP performs an indirect delivery. The forwarding IP address is the IP address of a router between the current IP node and the final destination. In an indirect delivery, the MAC address corresponding to the IP address of the router must be resolved.

---
Meaning that the packets would need to be examined to determine if the forwarding IP address is the address of your router.

As I also mentioned above, writing a system hook for winsock would also let you catch the socket functions, and would allow you to hook the connect(...) function. This would require significantly less code that writing a layered service provider.

Either way you go with this, it may be easier just to determine if the destination IP address is on the local subnet. If it is not, you would fail the outbound connection.

2.) The filtering won't help because there is no way to design a filter that says "deny all outbound traffic EXCEPT FOR destination address matching xxx.xxx.xxx.xxx and optional subrange mask". It is designed to filter out, not in.

3.) You can change the routing/gateway information for the local pc, **BUT**, if the gateway that handles the forwarding to the router is the same PC that handles the local intranet, then you won't be able to access any intranet based pc's. You haven't stated yet if your situation deals with one gateway, or two (local intranet, and internet). If there is only one gateway, then you have problems... disabling it on the local pc will in effect disable ALL network access.

---
Anyways, I will take a look at the system wide hook for you, as I do have some experience in this field. IMHO it is the simplest route to take, while still meeting your desired requirements.

Russell



My router is a NetScreen Router/Firewall, it is not a pc
my connection is as follows:

Internet<---->Modem<--->Router<---->Switch<---->Local network area (all the PCs + Server)

I tried this morning to change the default gateway ip, I lost internet connection, but I was still able to navigate trough shared files on the network.

Any solution is welcome. How does the MagicIp software do to change network params?

Thanx

I realize your router is not a pc, i was talking about the gateway (as in DHCP gateway). ;-)

Regarding how MagicIP works, I have not a clue....

But, on a better note, I may have something for you...

It is straight forward, easy to use, and provides a way to accurately determine ALL active connections, and allows you to close any desired connection. The functions come from iphlpapi.dll, and should work correctly on win98 through xp. Using this, it becomes simple to compare the local addr against the destination addr in order to determine if the address is internet. If the connection is internet, then you can close the connection. This checking/closing of the active connections could then be put into an efficient loop which would then effectively stop all traffic destined for the internet.

I still need some time to get this all together, but hopefully this works for you.

Russell


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

I did not yet try it.
Does the WinExecAsUser require some previledges or rights to run?

Thanx :)

When you do get around to trying it, let me know if you run into any issues...

It is pretty basic in principal: Once SetNetBlock is called, a high performance timer is created that calls back into the exposed proc every X ms, where you specify X in the dwResolution field of the TNetBlockInfo struct. This function then retrieves a list of all tcp connections. Depending on the blocking level, the first N bytes (2 for internet, 4 for all) are checked and if the comparison fails, the tcp connection is terminated. I recommend using something like 10-20ms for the resolution, because if the time is set too high, the browser may be able to make the connection, download and display the page, before the connection is killed. (the connection does get killed, but we are trying to stop the page from ever getting loaded as well). I found that even at a 10 ms resolution, the timer loop did not even nudge the CPU graph in Task Manager. As well, even with a T1 connection, I could not get a single page to load, connect to Messenger, or do any other outbound/inbound tcp connection because the loop killed it so quickly. (10ms gives you 100 checks/second).

Regarding permissions...
No, the CreateProcessWithLogonW does not require any special priveleges to execute. I tested this with the guest accout, which was able to launch an app with my main (admin) user account.

Regards,
Russell



Perfect!!

Everything works great, thank you.

Now that I know how to block internet, gonna finish my application. I may buy some more points if I need more help, would you still help me?

Again, thank you very much. I can send you money if you want.
Glad to hear it is working for you ;-)

And yes, I can/will help in the future, of course.

Regarding money.....
I will let it slide this time, but any further reference to $ will greatly offend me. I dedicate time here helping others as a way to "serve" the Delphi community (a community that has helped me greatly in return), as well as learn a few things along the way. I don't do this for profit.... thats what my day job is for ;-)

Russell



Okay, I won't talk of money anymore, but if you want a postcard from France or taste french sweeties I can send you.
Or maybe you'r in France, aren't you?

Anyway, my email is rthriller@excite.com, icq 11729214 and msn dathriller@hotmail.com, whatever you want, not to pay you but to thank you ;)

Bye
Hello

Is there any other code that blocks only specific port?

eq.

http://mysite.com = not block
BUT
ftp://mysite.com = block

or

http://localhost:8080 = block
and
http://localhost:3128 = not block

I hope someone's capable of this or has the code for a sample.

:)