How can I tell if the connection is metered?
Asked Answered
F

3

15

I wrote a program that monitors an IMAP email account. It runs on a schedule, on a laptop that I travel with. Sometimes it runs when my internet connection is through my mobile device, which has a metered connection (that is, I pay by the GB), and I don't want it to, because it uses a lot of bandwidth, and it can wait until bandwidth is free.

So the question is: how can a .NET program determine when the connection its using is metered?

Fatuous answered 20/4, 2013 at 16:10 Comment(9)
Is this Windows 8? I think Windows 8 has an 'is metered' property you can set on connections but I've not seen it on 7 or earlier.Thereabouts
I would be very surprised if this is possible to do, given an arbitrary network connection.Operable
@Rup: This is not a windows business. Unlike it contacts ISP and asks for link type.Adrianadriana
@Adrianadriana but Windows knows if it's using wifi or if it's using a USB modem, and that's what he's asking. Why would it need to ask the ISP?Thereabouts
@Rup: He is asking to not use bandwidth when it is costly i.e. when connecting via cell phone.Adrianadriana
@xaqron Sure, and his cell phone will appear to Windows as a USB modem won't it? So I think that Windows can identify when it is routing packets through his cell phone and know that's expensive, whereas you think it can't do that without asking his ISP?Thereabouts
@Rup: This is gonna turn to a chat. Also there are DSL modems plug by USB. You cannot rely on this. A USB modem i.e. for DSL line still can connect you to an unmetered link. Using RJ-45, USB, WiFi, Bluetooth... doesn't tell you about link financial plan. That's how ISP charge you according to your contract. A 3G operator may provide metered and unmetered plans at the same time so you cannot conclude connecting via SIM card always result in metered bandwidth.Adrianadriana
I wouldn't have thought this was so complicated. In Windows 8, you can manually designate that a connection is metered. That flag must be stored somewhere, and read either via API or maybe a direct registry read. I'm not trying to build a usage heuristic or anything, just read the manual setting.Fatuous
Windows 8.1 seems to detect this automatically when connecting to a phone. Outlook says it will work offline because of it.Willemstad
N
7

A brief search of MSDN found the NetworkInformation.GetInternetConnectionProfile function. It looks like it's officially part of the Metro interface, but I have heard that desktop applications can access most of the Metro libraries.

Naseby answered 14/11, 2013 at 0:5 Comment(0)
S
2

In 2021 you can use the powershell .NET framework and a registery KEY like that to test if your ethernet connection is set to metered:

$definition = @"
using System;
using System.Runtime.InteropServices;

namespace Win32Api
{

    public class NtDll
    {
        [DllImport("ntdll.dll", EntryPoint="RtlAdjustPrivilege")]
        public static extern int RtlAdjustPrivilege(ulong Privilege, bool Enable, bool CurrentThread, ref bool Enabled);
    }
}
"@

Add-Type -TypeDefinition $definition -PassThru | Out-Null
[Win32Api.NtDll]::RtlAdjustPrivilege(9, $true, $false, [ref]$false) | Out-Null

#Setting ownership to Administrators
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\DefaultMediaCost",[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::takeownership)
$acl = $key.GetAccessControl()
# Use your account "Administrators" or any other which is actually an existing one on your account
$acl.SetOwner([System.Security.Principal.NTAccount]"Administrators")
$key.SetAccessControl($acl)

#Giving Administrators full control to the key
$rule = New-Object System.Security.AccessControl.RegistryAccessRule ([System.Security.Principal.NTAccount]"Administrators","FullControl","Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)
$path = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\DefaultMediaCost"
# you can check for "Ethernet" "Wifi" "4G" etc.
$name = "Ethernet"
#If the Value is 2 = metered
New-ItemProperty -Path $path -Name $name -Value "2" -PropertyType DWORD -Force | Out-Null

If you get the following error:

Exception calling "SetAccessRule" with "1" argument(s): "Some or all identity references could not be translated.".

Try to change the "Administrators" user to any other on your account which exists and has admin rights.

Sturmabteilung answered 18/2, 2021 at 13:45 Comment(1)
Hmm, congrats on finding a solution but I don't like the idea of having to change registry permissions. There must be another way to find this.Thereabouts
C
1

A three-liner from github. I added a line.

[void][Windows.Networking.Connectivity.NetworkInformation, Windows, ContentType = WindowsRuntime]
$cost = [Windows.Networking.Connectivity.NetworkInformation]::
  GetInternetConnectionProfile().GetConnectionCost()
$metered = $cost.ApproachingDataLimit -or $cost.OverDataLimit -or $cost.Roaming -or
  $cost.BackgroundDataUsageRestricted -or ($cost.NetworkCostType -ne
  "Unrestricted")
[pscustomobject]@{Metered=$metered}
Metered
-------
  False
Castellatus answered 12/3 at 17:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.