# Virtual Machine Detection

Node-locking associates a software license with a specific device using a unique identifier, often derived from hardware IDs. This ensures that each license remains tied to one machine.

In virtualized and containerized environments, hardware information reflects the virtual machine rather than the host device. This makes it more difficult to reliably bind licenses to the actual machine.

LicenseSpring addresses this with specialized methods designed for containers and virtualization. These methods accurately detect virtual environments, enabling precise device identification and consistent license enforcement.

This document describes LicenseSpring’s techniques for distinguishing virtual machine instances and explains how they strengthen software protection.

### Prerequisites

{% stepper %}
{% step %}

### Completed the Getting Started Tutorial

You should have completed the [**Getting Started**](https://docs.licensespring.com/sdks/tutorials/best-practices/broken-reference) Tutorial, specifically:

* Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
* Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
* Implemented basic license management, including license activations, deactivations, and both online and local license checks.
  {% endstep %}
  {% endstepper %}

### Working With Virtual Machines

The LicenseSpring SDKs offer a distinctive feature: the capability to detect virtual machine environments.

#### Supported VMs

| VM name            | Java | C++SDK | .Net SDK | Swift SDK |
| ------------------ | ---- | ------ | -------- | --------- |
| Parallels Desktop  | -    | \*     | -        | \* \[x] a |
| QEMU               | -    | \*     | -        | \*        |
| VirtualBox         | -    | \*     | -        | \*        |
| Windows Virtual PC | -    | \*     | -        | \*        |
| VMware             | -    | \*     | -        | \*        |
| Wine               | -    | \*     | -        | \*        |
| Xen Project        | -    | \*     | -        | \*        |
| Docker             | -    | \*     | -        | \*        |
| Microsoft Hyper-V  | -    | \*     | -        | \*        |
| Microsoft Azure    | -    | \*     | -        | \*        |
| bhyve              | -    | \*     | -        | \*        |
| FreeBSD Jail       | -    | \*     | -        | \*        |
| KVM                | -    | \*     | -        | \*        |
| LXC                | -    | \*     | -        | \*        |
| Lguest             | -    | \*     | -        | \*        |
| Linux-VServer      | -    | \*     | -        | \*        |
| OpenVZ             | -    | \*     | -        | \*        |
| Project ACRN       | -    | \*     | -        | \*        |
| Virtual Iron       | -    | \*     | -        | \*        |
| QNX Hypervisor     | -    | \*     | -        | \*        |
| UTM                | -    | \*     | -        | \*        |

#### Enabling Virtual Machine Detection

This functionality, designed to enhance software security, can be activated manually within your program through the SDK as shown below.

{% tabs %}
{% tab title="C++" %}

```cpp
ExtendedOptions options;

options->enableVMDetection( true );

std::shared_ptr<Configuration> configuration = Configuration::Create(
     EncryptStr( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" ), 
     EncryptStr( "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX" ), 
     EncryptStr( "XXXXXX" ), 
     appName, appVersion, options );
```

{% endtab %}

{% tab title="C#" %}

```csharp
var options = new LicenseSpring.ExtendedOptions();
options.EnableVMDetection = true; 

var configuration = new LicenseSpring.Configuration(
            apiKey: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", 
            sharedKey: "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX",
            productCode: "XXXXXX", 
            appName: "NAME",
            appVersion: "VERSION",
            extendedOptions: options );
```

{% endtab %}

{% tab title="Swift" %}

```swift
let extendedOptions = ExtendedOptions(enableVMDetection: true)
let configuration = Configuration(
   apiKey: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", 
   sharedKey: "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX",
   productCode: "XXXXXX", 
   extendedOptions: extendedOptions)
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Note: Virtual machine detection is disabled by default. This feature must be enabled to make use of any features mentioned throughout this tutorial.
{% endhint %}

{% hint style="warning" %}
We provide a separate DLL for VM detection in the C++ SDK package. Make sure you put this library with the LicenseSpring DLL. If it is not found, a VMDNotAvailableException will occur.
{% endhint %}

#### Detecting Whether Virtual Machine Detection is Enabled

After the configuration has been initialized, developers are able to detect whether virtual machine detection is currently activated with:

{% tabs %}
{% tab title="C++" %}

```cpp
if ( configuration->isVMDetectionEnabled ) {
    // VM detection is enabled.
}
```

{% endtab %}

{% tab title="C#" %}

```csharp
if ( configuration.IsVMDetectionEnabled ) {
    // VM detection is enabled.
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
if (configuration.IsVMDetectionEnabled ) {
    // VM detection is enabled.
}
```

{% endtab %}
{% endtabs %}

Within the C++ SDK, this can also be checked through the `ExtendedOptions` object, as shown below:

```cpp
if ( options->isVMDetectionEnabled ) {
    // VM detection is enabled.
}
```

#### Detecting Whether a User is on a Virtual Machine

The SDKs can also check for whether a specific user currently using the application is on a virtual machine by using:

{% tabs %}
{% tab title="C++" %}

```cpp
if ( configuration->isVM() ) {
  // the user is currently running on a VM
}
```

{% endtab %}

{% tab title="C#" %}

```csharp
if ( configuration.IsVM ) {
  // the user is currently running on a VM
}       
```

{% endtab %}

{% tab title="Swift" %}

```swift
if ( configuration.isVM ) {
  // the user is currently running on a VM
}
```

{% endtab %}
{% endtabs %}

#### Retrieving Detected Virtual Machine Name

Developers can get the name of the user's hypervisor with the following:

{% tabs %}
{% tab title="C++" %}

```cpp
vmName = configuration->getDetectedVMName()
```

{% endtab %}

{% tab title="C#" %}

```csharp
vmName = configuration.GetDetectedVMName()
```

{% endtab %}

{% tab title="Swift" %}

```swift
let vmName = configuration.detectedVMName
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
VMDNotAvailableException (Windows only): Thrown in the C++ and .NET SDK in the case that VM detection dll is not found, tampered or detection failed.
{% endhint %}

### Preventing Virtual Machine Access

Licenses can also be restricted from activating on virtual machines through configuration settings. By selecting the “prevent virtual machine” option in the license settings, activation attempts within virtualized environments are blocked. This ensures that the software operates only on approved physical devices, in line with product requirements.

![Prevent Virtual Machine](https://content.gitbook.com/content/gLzurdfXUuKr9IziZWLz/blobs/RT7dJz2KP9buzPyErqfl/b09Vqr96cHaORTbHk0sT6_image.png)

When this feature is checked off, any actions involving our license will result in an error/exception, making the license unusable on a VM.

Within the SDK, developers can check for whether a license is allowed to work under virtual machine or not with:

```cpp
if ( license->isVMAllowed ) {
    // VM detection is enabled.
}
```

{% hint style="danger" %}
VMIsNotAllowedException: Thrown on virtual machine when VM detection is enabled but product policy prohibits running on VM.
{% endhint %}
