linux:apps:kvm:client-ipv6
Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| linux:apps:kvm:client-ipv6 [2026/09/15 20:17] – created oscar | linux:apps:kvm:client-ipv6 [2026/09/16 14:02] (current) – oscar | ||
|---|---|---|---|
| Line 3: | Line 3: | ||
| # Libvirt client IPv6 | # Libvirt client IPv6 | ||
| - | In **Debian**, when you apply the default `clean-traffic` network filter (`nwfilter`) to a virtual machine' | ||
| - | The `clean-traffic` filter | + | ## Overview |
| + | In **Debian** default Libvirt installation IPv6 is not configured. To enable | ||
| - | Here is how to properly configure it. | + | - Virtual Network setup `virbr0` |
| + | - Network filter (`nwfilter`) | ||
| - | ### Step 1: Ensure the Filter Configurations Exist | + | ## Virtual Network setup `virbr0` |
| + | The default virtual network can be inspected and changed in the `Virtual Machine Manager` (Edit -> Connection Details -> Virtual Networks) of via `virsh`. | ||
| + | |||
| + | #### Default Virtual Network Configuration | ||
| + | Inspect the current/ | ||
| + | ``` | ||
| + | # virsh net-dumpxml default | ||
| + | --------------------------- | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <forward mode=" | ||
| + | < | ||
| + | <port start=" | ||
| + | </ | ||
| + | </ | ||
| + | <bridge name=" | ||
| + | <mac address=" | ||
| + | <ip address=" | ||
| + | < | ||
| + | <range start=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | ``` | ||
| + | #### Edit Virtual Network Configuration | ||
| + | To edit and update the configuration with the following commands, where `default` is the name of the only/ | ||
| + | ``` | ||
| + | # virsh net-destroy default | ||
| + | # virsh net-edit default | ||
| + | # virsh net-start default | ||
| + | # systemctl restart libvirtd (** optional ** to restart whole libvirt) | ||
| + | ``` | ||
| + | With `virsh net-edit default` apply the following configuration: | ||
| + | ``` | ||
| + | # virsh net-dumpxml default | ||
| + | <network connections=' | ||
| + | < | ||
| + | < | ||
| + | <forward mode=' | ||
| + | <nat ipv6=' | ||
| + | <port start=' | ||
| + | </ | ||
| + | </ | ||
| + | <bridge name=' | ||
| + | <mac address=' | ||
| + | <ip address=' | ||
| + | < | ||
| + | <range start=' | ||
| + | </ | ||
| + | </ | ||
| + | <ip family=' | ||
| + | < | ||
| + | <range start=' | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ``` | ||
| + | ## Network filter (nwfilter) | ||
| + | In **Debian**, when the `default` configuration has applied the `clean-traffic` network filter (`nwfilter`) to VM network interface, **all IPv6 traffic is completely blocked by default**. | ||
| + | These network filters define the nft firewall setting that the host apply on the virbr0 bridge interface. | ||
| + | |||
| + | The `clean-traffic` filter is designed to prevent IP/MAC spoofing by only allowing IPv4 traffic matching the VM's assigned IP address. | ||
| + | |||
| + | ### Allow IPv6 Filter | ||
| + | To use IPv6 without removing this security filter, you must explicitly chain or include the `allow-ipv6` sub-filter. Here is how to properly configure it. | ||
| + | |||
| + | #### Step 1: Ensure the Filter Configurations Exist | ||
| On Debian, these default filters are provided by the `libvirt-daemon-config-nwfilter` package. Check if they are available in your system' | On Debian, these default filters are provided by the `libvirt-daemon-config-nwfilter` package. Check if they are available in your system' | ||
| - | ```bash | + | ``` |
| virsh nwfilter-list | virsh nwfilter-list | ||
| ``` | ``` | ||
| You should see both `clean-traffic` and `allow-ipv6` in the output. | You should see both `clean-traffic` and `allow-ipv6` in the output. | ||
| - | ### Step 2: Edit your Virtual Machine' | + | #### Step 2: Check active filter in your Virtual Machine' |
| - | You need to add the `allow-ipv6` filter reference inside the interface definition of your domain XML. | + | Open your VM configuration for editing (replace `your-vm-name` with your actual VM's name). Locate your network `< |
| - | + | ```bash | |
| - | 1. Open your VM configuration for editing (replace `your-vm-name` with your actual VM's name): | + | # virsh edit your-vm-name |
| - | | + | ``` |
| - | virsh edit your-vm-name | + | Example Configuration |
| - | ``` | + | |
| - | 2. Locate your network `< | + | |
| - | 3. If it only lists `clean-traffic`, modify it to include | + | |
| - | + | ||
| - | #### Example Configuration: | + | |
| ```xml | ```xml | ||
| < | < | ||
| Line 33: | Line 97: | ||
| <source bridge=' | <source bridge=' | ||
| <model type=' | <model type=' | ||
| - | <!-- Reference clean-traffic --> | ||
| < | < | ||
| - | <!-- Explicitly add the allow-ipv6 filter --> | ||
| - | < | ||
| </ | </ | ||
| ``` | ``` | ||
| + | We need to add the `allow-ipv6` filter to the configuration. But unfortunately we cannot simply add ` < | ||
| + | If doing so, we will get an error upon saving. `error: XML document failed to validate against schema: Unable to validate doc against / | ||
| - | Alternative: | + | The approach is to create |
| - | If you want strict anti-spoofing for both IPv4 and IPv6 (instead of a blanket "allow all IPv6" via allow-ipv6), | + | |
| - | you can combine clean-traffic | + | |
| - | [1] (https:// | + | |
| - | If using the default allow-ipv6, keep in mind that it acts as an open pass for IPv6 traffic through that interface. | + | #### Step 3: Create |
| - | If you require strict IPv6 source filtering, | + | |
| - | you must define the < | + | |
| - | [1] (https:// | + | |
| - | + | ||
| - | Step 3: Apply Changes | + | |
| - | For the changes to take effect on the guest networking stack: [1] (https:// | + | |
| - | 1. Save and exit the editor. | + | |
| - | 2. Completely stop and start the VM (a warm reboot inside the guest is usually not enough to reload host-side filter rules): | + | |
| - | + | ||
| - | virsh destroy your-vm-name | + | |
| - | virsh start your-vm-name | + | |
| - | + | ||
| - | + | ||
| - | # virsh edit error | + | |
| - | # virsh edit Debian13-ESP32-ARMHF | + | |
| - | error: XML document failed to validate against schema: Unable to validate doc against / | + | |
| - | Extra element devices in interleave | + | |
| - | Element domain failed to validate content | + | |
| - | + | ||
| - | Failed. Try again? [y, | + | |
| - | + | ||
| - | + | ||
| - | This error happens because libvirt' | + | |
| - | + | ||
| - | 1. Tag placement error: You accidentally pasted the < | + | |
| - | 2. Duplicate/ | + | |
| - | + | ||
| - | ## How to Fix It Right Now | + | |
| - | At the prompt Failed. Try again? [y, | + | |
| - | Carefully inspect your changes. The < | + | |
| - | ## Correct Structure: | + | |
| - | + | ||
| - | <domain type=' | + | |
| - | <!-- ... other configurations ... --> | + | |
| - | + | ||
| - | < | + | |
| - | <!-- ... other devices like disks, controllers ... --> | + | |
| - | + | ||
| - | < | + | |
| - | <mac address=' | + | |
| - | <source bridge=' | + | |
| - | <model type=' | + | |
| - | + | ||
| - | <!-- FILTERS GO HERE, INSIDE THE INTERFACE BLOCK --> | + | |
| - | < | + | |
| - | < | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | </ | + | |
| - | </ | + | |
| - | + | ||
| - | ## Common Pitfalls to Check: | + | |
| - | + | ||
| - | * | + | |
| - | * Did you place it after </ | + | |
| - | * Did you accidentally close < | + | |
| - | * | + | |
| - | + | ||
| - | ## The Escape Hatch (If your XML looks completely fine) | + | |
| - | If you look at the XML and everything is structurally perfect, libvirt might be choking on a different pre-existing element or space in a filepath somewhere else in your file. [4, 5, 6] | + | |
| - | You can force libvirt to ignore the validation schema and save your changes anyway by typing i at the prompt: [4, 7] | + | |
| - | + | ||
| - | Failed. Try again? [y, | + | |
| - | + | ||
| - | (Note: Only do this if you are certain your < | + | |
| - | If you hit y and look at the file, feel free to paste your < | + | |
| - | + | ||
| - | [1] [https:// | + | |
| - | [2] [https:// | + | |
| - | [3] [https:// | + | |
| - | [4] [https:// | + | |
| - | [5] [https:// | + | |
| - | [6] [https:// | + | |
| - | [7] [https:// | + | |
| - | + | ||
| - | The problem is that the Libvirt Domain XML schema only allows exactly one < | + | |
| - | While a custom | + | |
| - | You have two clean ways to fix this. | + | |
| - | ## Option 1: Combine filters into a custom file (Recommended & Cleanest) | + | |
| Instead of forcing two filters onto the interface, create a custom network filter file on the host machine that explicitly chains both functions together. | Instead of forcing two filters onto the interface, create a custom network filter file on the host machine that explicitly chains both functions together. | ||
| - | + | ``` | |
| - | 1. Create a new custom filter file on your Debian host: | + | # nano / |
| - | + | ``` | |
| - | | + | Paste the following configuration, |
| - | | + | ``` |
| - | 2. Paste the following configuration, | + | |
| - | | + | |
| < | < | ||
| < | < | ||
| < | < | ||
| </ | </ | ||
| - | + | ``` | |
| - | 3. Define and register the new filter in libvirt: | + | Define and register the new filter in libvirt: |
| - | + | ``` | |
| - | | + | # virsh nwfilter-define / |
| - | | + | ``` |
| - | 4. Update your VM XML to reference this single combined filter via virsh edit Debian13-ESP32-ARMHF: | + | Update your VM XML to reference this single combined filter via virsh edit Debian13-ESP32-ARMHF: |
| - | | + | ``` |
| + | # virsh edit your-vm-name | ||
| + | ``` | ||
| + | Replace the original filter `clean-traffic` with `clean-traffic-ipv6`: | ||
| + | ```xml | ||
| < | < | ||
| < | < | ||
| Line 152: | Line 134: | ||
| < | < | ||
| </ | </ | ||
| - | + | ``` | |
| - | + | Apply Changes. For the changes | |
| - | ## Option 2: Force it past the validation schema | + | 1. Save and exit the editor. |
| - | If you prefer not to create a custom file, you can instruct libvirt to completely bypass | + | 2. Completely stop and start the VM (a warm reboot inside |
| + | ``` | ||
| + | # virsh destroy your-vm-name | ||
| + | # virsh start your-vm-name | ||
| + | ``` | ||
| + | ### IPv6 Spoofing Filter | ||
| - | Failed. Try again? [y,n,i,f,?]: i | + | If using the default allow-ipv6, keep in mind that it acts as an open pass for IPv6 traffic through that interface. If you want strict anti-spoofing for both IPv4 and IPv6 (instead of a blanket "allow all IPv6" via allow-ipv6), you can combine clean-traffic with specific IPv6 variables, or reference a custom filter. |
| + | [1] (https:// | ||
| - | Why this works: The underlying libvirt processing engine handles multiple filter references perfectly fine at runtime, but its domain.rng checking tool is too strict and doesn't know it. Forcing | + | To include |
| - | (Note: | + | |
| - | Would you like to verify your operational | + | |
| - | [1] [https:// | + | #### Important Requirement: Passing the IPv6 Parameter |
| - | [2] [https:// | + | If you require strict IPv6 source filtering, you must define the < |
| + | The no-ipv6-spoofing filter requires libvirt | ||
| - | |||
| - | |||
| - | To include strict anti-spoofing protection for both IPv4 and IPv6, you should replace < | ||
| - | Do not keep allow-ipv6 in the file. The allow-ipv6 filter acts as a blanket permit for all IPv6 traffic, which would completely override and disable the security rules created by no-ipv6-spoofing. | ||
| Here is exactly how your / | Here is exactly how your / | ||
| - | + | ```xml | |
| - | <filter name=' | + | |
| - | < | + | |
| - | < | + | |
| - | </ | + | |
| - | + | ||
| - | ## Important Requirement: | + | |
| - | The no-ipv6-spoofing filter requires libvirt to know exactly which IPv6 address belongs to the virtual machine. Unlike IPv4 (where libvirt can automatically learn the IP via DHCP snooping), you must explicitly pass the allowed IPv6 address as a parameter inside your VM's XML configuration. | + | |
| - | Update your VM interface via virsh edit Debian13-ESP32-ARMHF to look like this: | + | |
| < | < | ||
| <mac address=' | <mac address=' | ||
| Line 186: | Line 160: | ||
| <model type=' | <model type=' | ||
| < | < | ||
| - | <!-- Replace with the actual IPv6 address assigned to this VM --> | + | <!-- Replace with the actual |
| + | < | ||
| < | < | ||
| </ | </ | ||
| <address type=' | <address type=' | ||
| </ | </ | ||
| + | </ | ||
| + | ``` | ||
| - | ## How this functions at the host level: | + | #### How this functions at the host level: |
| * clean-traffic builds filters to block any IPv4 or MAC spoofing attempts. | * clean-traffic builds filters to block any IPv4 or MAC spoofing attempts. | ||
| * no-ipv6-spoofing builds filters that drop any outgoing IPv6 packets whose source address does not match the exact IPV6 parameter value you provided. | * no-ipv6-spoofing builds filters that drop any outgoing IPv6 packets whose source address does not match the exact IPV6 parameter value you provided. | ||
| - | Would you like to know how to specify multiple IPv6 addresses if your VM uses both a global unicast address | + | ## Links |
| - | + | [1] (https:// | |
| - | + | [2] (https:// | |
| + | [3] (https:// | ||
linux/apps/kvm/client-ipv6.1789503426.txt.gz · Last modified: by oscar
