Internet Download Limiter: Euhemerus
Internet Download Limiter: Euhemerus
Euhemerus
6 Jul 2010CDDL
How to set a download limit and disable a user's network connection.
Download source code - 19.8 KB
Introduction
For those who have a capped download broadband package and have children, this article may
be a Godsend by showing a way to limit users' download ability by setting a daily download
allowance.
Background
So there I was, lecturing my children on the excess download charges our ISP had made again,
when it occured to me that what I need is someway of limiting their download capacity. After
searching the Web and asking in the CP forums, I came up with the idea for this little program.
Images
The actual program, when running, creates a permanent, very small window on the user's
desktop informing them of how much download capacity they have remaining.
Once the limit has been reached, the program informs the user that their limit has been reached
and that their Internet access is now disabled.
Hide Copy Code
' Instantiate our performance counter that will get the information we need.
downloadCounter = New PerformanceCounter("Network Interface", "Bytes
Received/sec", nicName)
We then keep a running total, and if the running total exceeds a predetermined limit, we disable
the user's network connection until the following day. It's as simple as that!
So, how do we implement all of this? How do we disable the user's internet connection I can hear
you asking. Easy! We stop the DHCP service on the user's computer. Now, here's the rub: if you
don't use dynamically allocated IP addresses from a DHCP server, stopping the client's DHCP
service isn't going to make any difference; it won't disable their connection :-(
Hide Copy Code
To be able to gather the downloaded bytes and keep a running total, we create an event that is
triggered every second and updates the latest download total. To create the trigger, we create a
one second timer:
Hide Copy Code
' Set the time interval for collecting the download data (milliseconds).
Dim myTimer As System.Timers.Timer = New System.Timers.Timer(1000)
We then create an Event Handler and point this to our Delegated collection Sub:
Hide Copy Code
Hide Copy Code
downloadBytes = downloadCounter.NextSample().RawValue
regKey.SetValue("PreviouslyDownloadedBytes", downloadBytes,
RegistryValueKind.DWord)
End Sub
Note: we also save a running total to the Registry. This is explained later.
disabled = True
StopService(service)
lblDownloadBytes.Text = "Download Limit Reached, Internet Access
Disabled."
End If
Else
' If we've reached the download limit, we stop the timer and remove the
event handler
' that monitors the downloaded bytes.
' No point in monitoring anymore something that isn't happening!
' We then rely on the AddressChanged sub to continue disabling the
network should the
' user restart the dhcp service.
TimerCounter.Stop()
RemoveHandler myTimer.Elapsed, AddressOf timer_Elapsed
End If
End Sub
As the program stands, as described, it would be pretty trivial to circumvent and regain network
access. So, we put in a few checks to help thwart circumvention. One of the first checks we
perform is to see if the computer has been restarted thus resetting our performance counter.
As can be seen from the previous code block, we set a couple of Registry entries. One of these
entries is 'Expired'. This is a boolean value that, if true, indicates that the download limit has been
reached. We check to see if we have 'expired' on startup, and if we have, we disable the DHCP
service straight away.
Another Registry setting we save, is the 'PreviouslyDownloadedBytes'. This is used in the event
that the user restarts their computer and hasn't exhausted their download limit for that day. We
subtract the PreviouslyDownloadedBytes figure from the limit we set, and this becomes the
new download limit for the remainder of the day.
Hide Copy Code
Case DateComparisonResult.TheSame
' We're running again on the same day. Check to make sure we've not expired.
If downloadLimitReached Then
lblDownloadBytes.Text = "Download Limit Reached, Internet Access Disabled."
disabled = True
StopService(service)
Else
' Adjust the download limit in case the computer has been restarted.
tempDownloadLimit = maxDownloadLimit - previouslyDownloadedBytes
End If
Another check performed is to see if the user has moved the system clock forward thus resetting
the download counter. One of our Registry entries saves the date on which we last ran, we then
compare this date to the system's current date on startup to determine if we should give the user
internet access. So that we can accurately determine if the system's clock is in fact correct, we
query an NTP time server. DaveyM69 created a very detailed and useful CP article on querying
time servers; see: http://www.codeproject.com/KB/datetime/SNTPClient.aspx for more
information. I have modified Dave's original SNTPClient code to suit my own needs, and used
this code to query a time server.
Hide Copy Code
' First check to see if the dhcp service is running, if not, start it.
' We need network access to communicate with an NTP server to check that
' the system clock hasn't been changed.
If Not IsServiceRunning(service) Then
StartService(service)
End If
' Make sure the nic is connected to the network before querying
' the NTP server.
If My.Computer.Network.IsAvailable Then
ntpServerDate = SntpClient.GetNow().ToShortDateString
End If
The last check we make is to monitor the state of the IP address assigned to the NIC. If we have
disabled the DHCP service and thus disabled the connection, and the NIC's IP address will be
non-existent. We set up an event handler which notifies us if the NIC's IP address changes.
Hide Copy Code
AddHandler NetworkChange.NetworkAddressChanged, AddressOf AddressChanged
We then use our delegated sub to disable the DHCP service again if the user re-enabled it.
Hide Copy Code
' We're notified here of an IP address change. If the network should have
been
' disabled and we reach here, it means the user has restarted the dhcp
service.
' So we stop it again.
If disabled Then
StopService(service)
End If
End Sub
So, there you have it ladies and gentlemen; how to simply disable a network connection after a
predetermined number of bytes have been downloaded.
Points of Interest
Because the instantiation of the performance counter requires the name of the NIC, we use a
WMI routine to get the NIC's name.
' Get the name of the nic that has an IP address associated with it.
Although we try and filter the number of NICs returned by our WMI query by using the:
Hide Copy Code
clause, we can sometimes get back more than one NIC. In this case, we check to see if the
returned NIC has a DHCP server address associated with it.
We also use in the program a routine to start the DHCP service. One of the problems I found was
that if you start the DHCP service and then try and use any network function immediately, the
function would fail even though we wait explicitly for the service to start by using:
Hide Copy Code
sc.WaitForStatus(ServiceControllerStatus.Running)
This is because, even though the service is running, it takes time for the DHCP server to allocate
an IP address to the NIC. To keep things simple, I just added a 5 second delay before we use any
network function.
Hide Copy Code
' Even though we wait for the status of the dhcp service to change to
' Running, we have to pause to give the dhcp server time to allocate
' an IP address to our Nic.
Thread.Sleep(5000)
Catch ex As Exception
lblDownloadBytes.Text = "Could Not Start DHCP Service"
End Try
End If
End Sub
Caveats
Although the program works well on Windows XP and Windows 7, the user must be a member of
the Administrators group. Additionally, on Vista, even if UAC is not disabled, UAC prompts will
appear when starting and stopping the DHCP service and trying to change the system time.
To Do
I think, to overcome the running as admin and UAC problems, everything that doesn't display
information to the user should become a Windows service with a separate GUI app that
communicates with the service to display to the user their current download usage.
One other thing: if the user stops our app in the Task Manager, obviously we can't monitor
download usage. I've been thinking about adding to the form closing event a routine that shuts
down the user's computer if they stop our app. Also, it might be an idea integrating our app in
such a way that if it's not running at startup, the NIC itself can't start; possibly by relying on our
app to, say, start the NIC's driver.
History
4th July 2010 - Initial version.
5th July 2010 - Bug fix.
License
This article, along with any associated source code and files, is licensed under The Common
Development and Distribution License (CDDL)