diff --git a/net/ndp-proxy-go/Makefile b/net/ndp-proxy-go/Makefile
new file mode 100644
index 0000000000..a1375b02b7
--- /dev/null
+++ b/net/ndp-proxy-go/Makefile
@@ -0,0 +1,7 @@
+PLUGIN_NAME= ndp-proxy-go
+PLUGIN_VERSION= 0.1
+PLUGIN_COMMENT= IPv6 Neighbor Discovery Protocol Proxy
+PLUGIN_MAINTAINER= cedrik@pischem.com
+PLUGIN_DEPENDS= ndp-proxy-go
+
+.include "../../Mk/plugins.mk"
diff --git a/net/ndp-proxy-go/pkg-descr b/net/ndp-proxy-go/pkg-descr
new file mode 100644
index 0000000000..458bfea7df
--- /dev/null
+++ b/net/ndp-proxy-go/pkg-descr
@@ -0,0 +1,8 @@
+IPv6 Neighbor Discovery (ND), Router Advertisement (RA) and Duplicate Address Detection (DAD) Proxy
+
+Plugin Changelog
+================
+
+0.1
+
+* Initial Release
diff --git a/net/ndp-proxy-go/src/etc/inc/plugins.inc.d/ndpproxy.inc b/net/ndp-proxy-go/src/etc/inc/plugins.inc.d/ndpproxy.inc
new file mode 100644
index 0000000000..52b0f5b251
--- /dev/null
+++ b/net/ndp-proxy-go/src/etc/inc/plugins.inc.d/ndpproxy.inc
@@ -0,0 +1,66 @@
+ gettext('NDP Proxy'),
+ 'configd' => [
+ 'start' => ['ndpproxy start'],
+ 'restart' => ['ndpproxy restart'],
+ 'stop' => ['ndpproxy stop'],
+ ],
+ 'name' => 'ndpproxy',
+ 'pidfile' => '/var/run/ndp_proxy_go.pid'
+ ];
+ }
+
+ return $services;
+}
+
+function ndpproxy_xmlrpc_sync()
+{
+ $result = [];
+
+ $result[] = array(
+ 'description' => gettext('NDP Proxy'),
+ 'section' => 'OPNsense.ndpproxy',
+ 'id' => 'ndpproxy',
+ 'services' => ["ndpproxy"],
+ );
+
+ return $result;
+}
diff --git a/net/ndp-proxy-go/src/opnsense/mvc/app/controllers/OPNsense/NdpProxy/Api/GeneralController.php b/net/ndp-proxy-go/src/opnsense/mvc/app/controllers/OPNsense/NdpProxy/Api/GeneralController.php
new file mode 100644
index 0000000000..34d1fb3fe5
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/mvc/app/controllers/OPNsense/NdpProxy/Api/GeneralController.php
@@ -0,0 +1,40 @@
+view->pick('OPNsense/NdpProxy/general');
+ $this->view->generalForm = $this->getForm("general");
+ }
+}
diff --git a/net/ndp-proxy-go/src/opnsense/mvc/app/controllers/OPNsense/NdpProxy/forms/general.xml b/net/ndp-proxy-go/src/opnsense/mvc/app/controllers/OPNsense/NdpProxy/forms/general.xml
new file mode 100644
index 0000000000..1d8422d653
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/mvc/app/controllers/OPNsense/NdpProxy/forms/general.xml
@@ -0,0 +1,79 @@
+
diff --git a/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/ACL/ACL.xml b/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/ACL/ACL.xml
new file mode 100644
index 0000000000..b70514587e
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/ACL/ACL.xml
@@ -0,0 +1,17 @@
+
+
+ Services: NDP Proxy: General Settings
+ Allow access to NDP Proxy General Settings
+
+ ui/ndpproxy/general/*
+ api/ndpproxy/general/*
+
+
+
+ Services: NDP Proxy: Log File
+
+ ui/diagnostics/log/core/ndpproxy/*
+ api/diagnostics/log/core/ndpproxy/*
+
+
+
diff --git a/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/Menu/Menu.xml b/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/Menu/Menu.xml
new file mode 100644
index 0000000000..7efc570587
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/Menu/Menu.xml
@@ -0,0 +1,8 @@
+
diff --git a/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/NdpProxy.php b/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/NdpProxy.php
new file mode 100644
index 0000000000..5831f6887a
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/NdpProxy.php
@@ -0,0 +1,68 @@
+general->enabled->isEqual('1')) {
+ foreach (['upstream', 'downstream'] as $field) {
+ if ($this->general->$field->isEmpty()) {
+ $messages->appendMessage(new Message(
+ gettext('Interface is required.'),
+ "general.$field"
+ ));
+ }
+ }
+
+ $upstream = $this->general->upstream->getValue();
+ $downstreamList = array_filter(explode(',', $this->general->downstream->getValue()));
+
+ if (!empty($upstream) && in_array($upstream, $downstreamList, true)) {
+ $messages->appendMessage(new Message(
+ gettext('Downstream interfaces cannot contain upstream interface.'),
+ 'general.downstream'
+ ));
+ }
+ }
+ }
+
+ public function performValidation($validateFullModel = false)
+ {
+ $messages = parent::performValidation($validateFullModel);
+ $this->checkConfiguration($messages);
+ return $messages;
+ }
+}
diff --git a/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/NdpProxy.xml b/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/NdpProxy.xml
new file mode 100644
index 0000000000..c9239abfc1
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/mvc/app/models/OPNsense/NdpProxy/NdpProxy.xml
@@ -0,0 +1,41 @@
+
+ //OPNsense/ndpproxy
+ NDP Proxy model
+ 0.2
+
+
+
+ 0
+ Y
+
+
+
+ Y
+
+
+ 1
+ Y
+
+
+ 1
+ Y
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 0
+ Y
+
+
+
+
diff --git a/net/ndp-proxy-go/src/opnsense/mvc/app/views/OPNsense/NdpProxy/general.volt b/net/ndp-proxy-go/src/opnsense/mvc/app/views/OPNsense/NdpProxy/general.volt
new file mode 100644
index 0000000000..5601b92bd5
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/mvc/app/views/OPNsense/NdpProxy/general.volt
@@ -0,0 +1,49 @@
+{#
+ # Copyright (c) 2025 Cedrik Pischem
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without modification,
+ # are permitted provided that the following conditions are met:
+ #
+ # 1. Redistributions of source code must retain the above copyright notice,
+ # this list of conditions and the following disclaimer.
+ #
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
+ # this list of conditions and the following disclaimer in the documentation
+ # and/or other materials provided with the distribution.
+ #
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ # AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ # POSSIBILITY OF SUCH DAMAGE.
+ #}
+
+
+
+
+ {{ partial("layout_partials/base_form", ['fields': generalForm, 'id': 'frm_GeneralSettings']) }}
+
+{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/ndpproxy/service/reconfigure', 'data_service_widget': 'ndpproxy'}) }}
+
diff --git a/net/ndp-proxy-go/src/opnsense/service/conf/actions.d/actions_ndpproxy.conf b/net/ndp-proxy-go/src/opnsense/service/conf/actions.d/actions_ndpproxy.conf
new file mode 100644
index 0000000000..f5fcf8731d
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/service/conf/actions.d/actions_ndpproxy.conf
@@ -0,0 +1,24 @@
+[start]
+command:service ndp-proxy-go start
+parameters:
+type:script
+message:Starting NDP Proxy service
+
+[stop]
+command:service ndp-proxy-go stop
+parameters:
+type:script
+message:Stopping NDP Proxy service
+
+[restart]
+command:service ndp-proxy-go restart
+parameters:
+type:script
+message:Restarting NDP Proxy service
+description:Restart NDP Proxy service
+
+[status]
+command:service ndp-proxy-go status
+parameters:
+type:script_output
+message:Requesting NDP Proxy status
diff --git a/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/NdpProxy/+TARGETS b/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/NdpProxy/+TARGETS
new file mode 100644
index 0000000000..a75c8d5120
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/NdpProxy/+TARGETS
@@ -0,0 +1 @@
+ndp_proxy_go:/etc/rc.conf.d/ndp_proxy_go
diff --git a/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/NdpProxy/ndp_proxy_go b/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/NdpProxy/ndp_proxy_go
new file mode 100644
index 0000000000..c75534e6a0
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/NdpProxy/ndp_proxy_go
@@ -0,0 +1,38 @@
+# DO NOT EDIT THIS FILE -- OPNsense auto-generated file
+{% set general = helpers.getNodeByTag('OPNsense.ndpproxy.general') %}
+{% if general.enabled|default("0") == "1" and general.upstream and general.downstream %}
+ndp_proxy_go_enable="YES"
+ndp_proxy_go_upstream="{{ helpers.physical_interface(general.upstream) }}"
+{% set downstream_interfaces = [] %}
+{% for interface in general.downstream.split(',') %}
+{% do downstream_interfaces.append(helpers.physical_interface(interface)) %}
+{% endfor %}
+ndp_proxy_go_downstream="{{ downstream_interfaces|join(' ') }}"
+{% set flags = [] %}
+{% if general.debug == "1" %}
+{% do flags.append('--debug') %}
+{% endif %}
+{% if general.ra == "0" %}
+{% do flags.append('--no-ra') %}
+{% endif %}
+{% if general.routes == "0" %}
+{% do flags.append('--no-routes') %}
+{% endif %}
+{% if general.cache_ttl %}
+{% do flags.append('--cache-ttl ' ~ general.cache_ttl ~ 'm') %}
+{% endif %}
+{% if general.cache_max %}
+{% do flags.append('--cache-max ' ~ general.cache_max) %}
+{% endif %}
+{% if general.route_qps %}
+{% do flags.append('--route-qps ' ~ general.route_qps) %}
+{% endif %}
+{% if general.pcap_timeout %}
+{% do flags.append('--pcap-timeout ' ~ general.pcap_timeout ~ 'ms') %}
+{% endif %}
+{% if flags|length > 0 %}
+ndp_proxy_go_flags="{{ flags|join(' ') }}"
+{% endif %}
+{% else %}
+ndp_proxy_go_enable="NO"
+{% endif %}
diff --git a/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/Syslog/local/ndpproxy.conf b/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/Syslog/local/ndpproxy.conf
new file mode 100644
index 0000000000..302335e1c9
--- /dev/null
+++ b/net/ndp-proxy-go/src/opnsense/service/templates/OPNsense/Syslog/local/ndpproxy.conf
@@ -0,0 +1,6 @@
+###################################################################
+# Local syslog-ng configuration [ndpproxy].
+###################################################################
+filter f_local_ndpproxy {
+ program("ndpproxy");
+};