diff --git a/src/opnsense/mvc/app/models/OPNsense/Firewall/Alias.xml b/src/opnsense/mvc/app/models/OPNsense/Firewall/Alias.xml
index cb707ad26..edd60c21d 100644
--- a/src/opnsense/mvc/app/models/OPNsense/Firewall/Alias.xml
+++ b/src/opnsense/mvc/app/models/OPNsense/Firewall/Alias.xml
@@ -37,6 +37,7 @@
Network group
MAC address
External (advanced)
+ IPv6 Dynamic Host
@@ -46,6 +47,8 @@
IPv6
+
+
0
diff --git a/src/opnsense/mvc/app/views/OPNsense/Firewall/alias.volt b/src/opnsense/mvc/app/views/OPNsense/Firewall/alias.volt
index ba001896d..d7e779291 100644
--- a/src/opnsense/mvc/app/views/OPNsense/Firewall/alias.volt
+++ b/src/opnsense/mvc/app/views/OPNsense/Firewall/alias.volt
@@ -215,6 +215,11 @@
$("#copy-paste").show();
break;
}
+ if ($(this).val() === 'dynipv6host') {
+ $("#row_alias\\.dyninterface").show();
+ } else {
+ $("#row_alias\\.dyninterface").hide();
+ }
if ($(this).val() === 'port') {
$("#row_alias\\.counters").hide();
} else {
@@ -472,6 +477,7 @@
+
@@ -691,6 +697,23 @@
+
+
+
+
+ {{lang._('dyninterface')}}
+
+ |
+
+
+
+ {{lang._('Select the dyninterface for the V6 dynamic IP')}}
+
+ |
+
+
+ |
+
diff --git a/src/opnsense/scripts/filter/lib/alias.py b/src/opnsense/scripts/filter/lib/alias.py
index 1ec10e20c..0de730c0c 100755
--- a/src/opnsense/scripts/filter/lib/alias.py
+++ b/src/opnsense/scripts/filter/lib/alias.py
@@ -26,6 +26,9 @@
--------------------------------------------------------------------------------------
Alias representation
"""
+import socket
+import fcntl
+import struct
import os
import re
import time
@@ -33,6 +36,7 @@ import requests
import ipaddress
import dns.resolver
import syslog
+import subprocess
from hashlib import md5
from . import geoip
from .arpcache import ArpCache
@@ -57,6 +61,7 @@ class Alias(object):
self._timeout = timeout
self._name = None
self._type = None
+ self._dyninterface = None
self._proto = 'IPv4,IPv6'
self._items = list()
self._resolve_content = set()
@@ -67,6 +72,8 @@ class Alias(object):
self._proto = subelem.text
elif subelem.tag == 'name':
self._name = subelem.text
+ elif subelem.tag == 'dyninterface':
+ self._dyninterface = subelem.text
elif subelem.tag == 'ttl':
tmp = subelem.text.strip()
if len(tmp.split('.')) <= 2 and tmp.replace('.', '').isdigit():
@@ -259,6 +266,31 @@ class Alias(object):
# return the addresses and networks of this alias
return list(self._resolve_content)
+ def _fetch_dynipv6(self, address):
+
+ #get the interface /64 address
+ address = address.strip()
+ sp = subprocess.run(['/sbin/ifconfig', self._dyninterface,'inet6'], capture_output=True, text=True)
+ for line in sp.stdout.split('\n'):
+ if line.find('prefixlen 64') > -1:
+ i_address = line.split(' ')[1]
+ if i_address[0] == '1' or i_address[0] == '2' or i_address[0] == 3:
+ break
+ # split the mask - if no mask it's a /64
+ if address.find('/') > -1:
+ l_address,l_mask = address.split('/')
+ else:
+ l_mask = '64'
+ l_address = address
+
+ base_mask = int(l_mask)
+ base_address = ipaddress.ip_address(i_address)
+ base_size=int((128-base_mask)/16)
+ combine_address='0'+l_address
+ ipv6_addr = ipaddress.ip_address(combine_address)
+ calculated_address = ':'.join(base_address.exploded.split(':')[:8-base_size] + ipv6_addr.exploded.split(':')[8-base_size:])
+ for address in self._parse_address(calculated_address):
+ yield address
def get_parser(self):
""" fetch address parser to use, None if alias type is not handled here
:return: function or None
@@ -269,6 +301,8 @@ class Alias(object):
return self._fetch_url
elif self._type == 'geoip':
return self._fetch_geo
+ elif self._type == 'dynipv6host':
+ return self._fetch_dynipv6
elif self._type == 'mac':
return ArpCache().iter_addresses
else:
diff --git a/src/opnsense/service/templates/OPNsense/Filter/filter_tables.conf b/src/opnsense/service/templates/OPNsense/Filter/filter_tables.conf
index 4deb0b013..c241dfab1 100644
--- a/src/opnsense/service/templates/OPNsense/Filter/filter_tables.conf
+++ b/src/opnsense/service/templates/OPNsense/Filter/filter_tables.conf
@@ -5,6 +5,8 @@
{% endif %}
{% set new_style_aliases = 0 %}
+{# Macro import #}
+{% from 'OPNsense/Macros/interface.macro' import physical_interface %}
{% if helpers.exists('OPNsense.Firewall.Alias.aliases.alias') %}
{% set new_style_aliases = OPNsense.Firewall.Alias.aliases.alias|length %}
{% for alias in helpers.toList('OPNsense.Firewall.Alias.aliases.alias') %}
@@ -21,6 +23,8 @@
{{ alias.content|e|encode_idna }}
{% elif alias.content %}
{{ alias.content|e|encode_idna }}
+{% endif %}{% if alias.dyninterface %}
+ {{ physical_interface(alias.dyninterface)|default('LAN')
{% endif %}{% if alias.proto %}
{{ alias.proto|e }}
{% endif %}{% if alias.updatefreq %}
|