Edit: As of the latest version of Virtualizor, this tutorial is no longer needed!
For our VPS service, we choose to use Virtualizor instead of SolusVM due to its end user interface, which is easier and looks more modern than Solus. We noticed Virtualizor ebtables rules do not include anything to protect IPv6 subnets, so we created our own hook scripts so users cannot change their assigned IPv6 to anything they want.
How we did it? We first created three simple helper scripts:
#!/bin/bash #This script matches the mac with the IPv6 subnet vmname=$1 vmmac=$2 ip6=$(/usr/local/sbin/ipv6_shorten.py $3) mask=$4 tstp=$(date +"%s") cmd="-A vm${vmname} -p IPv6 -s ${vmmac} --ip6-src ${ip6}${mask} -j ACCEPT" sleep 5 /sbin/ebtables -t filter ${cmd} echo "${tstp} - Adding rule \"${cmd}\" retcode $?" >> /var/log/ebtables_ipv6.log
#!/bin/bash #This script allows the subnet to be forwarded vmname=$1 tstp=$(date +"%s") cmd="-A FORWARD -p IPv6 -i viif${vmname} -j vm${vmname}" sleep 5 if [ $(/sbin/ebtables-save | grep -Fxc -- "${cmd}") -gt 0 ] then echo "${tstp} - IPv6 FORWARD rule for \"${vmname}\" already in place" >> /var/log/ebtables_ipv6.log else /sbin/ebtables -t filter ${cmd} echo "${tstp} - Adding rule \"${cmd}\" retcode $?" >> /var/log/ebtables_ipv6.log fi
#!/usr/bin/env python3 #This tiny python3 script shortens IPv6 addresses! import sys import ipaddress if __name__ == "__main__": if(len(sys.argv) == 1): ips = [item.strip() for item in sys.stdin.readlines()] for ipv6 in ips: print(ipaddress.ip_address(ipv6)) elif (len(sys.argv) == 2): print(ipaddress.ip_address(sys.argv[1]))
And finally, the hook to after_startvps.php in Virtualizor!
<?php function __after_startvps($vps){ // Write your code here. e.g. You can add additional parameters in the config file of the the VPS. // List the IPs $res = makequery("SELECT i.*, ip.* FROM ips i LEFT JOIN ippool ip ON (ip.ippid = i.ippid) WHERE i.vpsid = :vid ORDER BY `primary` DESC", array(':vid' => $vps['vpsid'])); for($i=0; $i < vsql_num_rows($res); $i++){ $ips[$i] = vsql_fetch_assoc($res); } ////// $path = '/etc/libvirt/qemu/'.$vps['vps_name'].'.xml'; $doc = new DOMDocument; $doc->load($path); $root = $doc->documentElement; $mac0tag = $root->getElementsByTagName('mac')->item(0); $mac_addr = $mac0tag->getAttribute('address'); ////// //file_put_contents('/tmp/ips',var_export($ips,true)); $vps_name = $vps['vps_name']; //$mac_addr = $vps['mac']; $ipv6 = array(); $ipv6_m = array(); //file_put_contents('/tmp/ids.txt', $vps_name." ".$mac_addr); for($i=0;$i < count($ips); $i++){ if($ips[$i]['ipv6'] == '1' ){ $ipv6[] = $ips[$i]['ip']; $ipv6_m[] = $ips[$i]['ipr_netmask']; } } //file_put_contents('/tmp/ips2',var_export($ipv6,true)); $out1 = shell_exec('/usr/local/sbin/ipv6_ebtables_fwd.sh '.$vps_name); for($i=0;$i < count($ipv6); $i++){ if(is_numeric($ipv6_m[$i])){ $ipv6_m[$i] = '/'.$ipv6_m[$i]; } $out2[$i] = shell_exec('/usr/local/sbin/ipv6_ebtables_srcmac.sh '.$vps_name.' '.$mac_addr.' '.$ipv6[$i].' '.$ipv6_m[$i]); } } ?>
Now you should be able to make Virtualizor VPS unable to use any other IPv6 subnet, besides the assigned one. You can check if it is adding rules by using “ebtables-save” as root.
Beware these scripts were only tested when assigning /64 subnets! Good luck!