diff --git a/core/DapGeoIP.h b/core/DapGeoIP.h
index a6682327fd0e16b0e1a5c39d41357fda26ea94f9..333dbef22f30eb8de8d36b82d829a4c9f12cebbf 100644
--- a/core/DapGeoIP.h
+++ b/core/DapGeoIP.h
@@ -12,9 +12,8 @@
 
 #include "maxminddb/maxminddb.h"
 
-#define PATH_TO_DB ":/GeoLite2-Country.mmdb"
-// #define PATH_TO_DB "/home/danilmartynenko/untitled/GeoLite2-Country.mmdb"
-// #define PATH_TO_DB QCoreApplication::applicationDirPath() + "/GeoLite2-Country.mmdb"
+#define PATH_TO_DB ":/GeoLite2-Country.mmdb" //21.02.2025
+// #define PATH_TO_DB ":/GeoLite2-City.mmdb" //21.02.2025
 
 class DapGeoIP : public QObject
 {
diff --git a/vpn/client/DapCmdHandlers/DapCmdConnect.cpp b/vpn/client/DapCmdHandlers/DapCmdConnect.cpp
index fe9b4ffd0ac246df7614f06661d5d439679b2bbe..345c3c2620cb2466cf92a118fdb011df810ec3c0 100644
--- a/vpn/client/DapCmdHandlers/DapCmdConnect.cpp
+++ b/vpn/client/DapCmdHandlers/DapCmdConnect.cpp
@@ -71,7 +71,9 @@ void DapCmdConnect::handle(const QJsonObject* params)
     QMap<QString, QJsonValue> mandatoryConnParams = {
         {ADDRESS_KEY, params->value(ADDRESS_KEY)},
         {PORT_KEY, params->value(PORT_KEY)},
-        {UPDATE_ROUTE_TABLE, params->value(UPDATE_ROUTE_TABLE)}
+        {UPDATE_ROUTE_TABLE, params->value(UPDATE_ROUTE_TABLE)},
+        {RUN_SCRIPT_PATH, params->value(RUN_SCRIPT_PATH)},
+        {RUN_SCRIPT_AFTER_CONNECT, params->value(RUN_SCRIPT_AFTER_CONNECT)}
     };
 
     if (!mandatoryConnParams[ADDRESS_KEY].isString() || !mandatoryConnParams[PORT_KEY].isDouble()) {
@@ -93,6 +95,14 @@ void DapCmdConnect::handle(const QJsonObject* params)
     uint16_t port = uint16_t(mandatoryConnParams[PORT_KEY].toInt());
     QString address = mandatoryConnParams[ADDRESS_KEY].toString();
 
+    QString runScriptPath = mandatoryConnParams[RUN_SCRIPT_PATH].toString();
+
+    if (!runScriptPath.isEmpty()) {
+        bool runAfterConnect = mandatoryConnParams[RUN_SCRIPT_AFTER_CONNECT].toBool(true);
+        qDebug() << "Running script path:" << runScriptPath << "Run after connect:" << runAfterConnect;
+        emit sigSetRunScript(runScriptPath, runAfterConnect);
+    }
+
     qDebug() << "Address:" << address << ", Port:" << port << ", UpdateRouteTable:" << updateRouteTable;
     qDebug() << "SerialKey:" << (serialKey.isEmpty() ? "No serial key provided" : "Serial key provided");
 
diff --git a/vpn/client/DapCmdHandlers/DapCmdConnect.h b/vpn/client/DapCmdHandlers/DapCmdConnect.h
index 7786d0f50e589511a4e1baa569d9ff9ed5b68346..1d8bac67d60f5b43a5ce8c18606ed5e2b19c8553 100644
--- a/vpn/client/DapCmdHandlers/DapCmdConnect.h
+++ b/vpn/client/DapCmdHandlers/DapCmdConnect.h
@@ -24,6 +24,7 @@ signals:
     void sigConnectNoAuth(const QString& address, uint16_t port);
     void sigDisconnect();
     void sigRestartService(bool if_runnning);
+    void sigSetRunScript(const QString& runScriptPath, bool runAfterConnect);
 
 private:
     const QString ACTION_KEY = "action";
@@ -33,6 +34,8 @@ private:
     const QString ADDRESS_KEY = "address";
     const QString PORT_KEY = "port";
     const QString UPDATE_ROUTE_TABLE = "updateRouteTable";
+    const QString RUN_SCRIPT_PATH = "run_script_path";
+    const QString RUN_SCRIPT_AFTER_CONNECT = "run_script_after_connect";
 
     const QString CODE_KEY = "code";
     const QString MESSAGE_KEY = "message";
diff --git a/vpn/client/darwin/DapUtun.cpp b/vpn/client/darwin/DapUtun.cpp
index fbb024a11cb09319c23034ba1114bebd0c77571c..559473d2093525e51d54e1fe2607b1ff799b8a25 100644
--- a/vpn/client/darwin/DapUtun.cpp
+++ b/vpn/client/darwin/DapUtun.cpp
@@ -21,38 +21,11 @@ This file is part of DAP UI SDK the open source project
    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <QtDebug>
-#include <QProcess>
-#include <QFile>
-
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/sys_domain.h>
-#include <sys/kern_control.h>
-#include <net/if_utun.h>
-#include <errno.h>
-#include <string.h>
-
-#include <unistd.h>
-#include <fcntl.h>
-
-
-
 #include "DapUtils.h"
-#include "DapTunUnixAbstract.h"
-#include "QtCore/qdebug.h"
 #include "darwin/DapUtun.h"
-#include "DapTunWorkerUnix.h"
-#include "DapNetworkMonitor.h"
-#include "SigUnixHandler.h"
 
-/**
- * @brief DapUtun::DapUtun
- */
 DapUtun::DapUtun()
-    :DapTunUnixAbstract()
+    : DapTunUnixAbstract()
 {
     // List of Apple addresses needed to be routed directly through the tunnel
     appleAdditionalRoutes = QStringList({
@@ -71,50 +44,81 @@ DapUtun::DapUtun()
             this, &DapUtun::tunDeviceDestroy, Qt::DirectConnection);
 }
 
-/**
- * @brief DapUtun::requestTunDeviceCreate
- */
+
+void DapUtun::executeCommand(const QString &cmd)
+{
+    qDebug() << "Executing command:" << cmd;
+
+    QProcess process;
+    process.start(cmd);
+
+    if (!process.waitForFinished(2000)) {
+        qWarning() << "Command failed to execute:" << process.errorString();
+        return;
+    }
+
+    int ret = process.exitCode();
+    QString output = process.readAllStandardOutput();
+    QString errorOutput = process.readAllStandardError();
+
+    qDebug() << "Command output:" << output.trimmed();
+    if (!errorOutput.isEmpty()) {
+        qWarning() << "Command error output:" << errorOutput.trimmed();
+    }
+
+    qDebug() << "Command returned exit code:" << ret;
+    if (ret != 0) {
+        qWarning() << "Command failed with exit code:" << ret;
+    }
+}
+
 void DapUtun::tunDeviceCreate()
 {
     qDebug() << "[DapUtun::tunDeviceCreate]";
+
     if (m_tunSocket > 0) {
         qInfo() << "Socket already open";
         return;
     }
-    // Prepare structs
+
+    // Lambda function to retrieve error messages
+    auto getErrorString = []() -> QString {
+        int err = errno;
+        char errbuf[256];
+        ::strerror_r(err, errbuf, sizeof(errbuf));
+        return QString("%1 (code %2)").arg(errbuf).arg(err);
+    };
+
+    // Initialize the control structure
     struct ctl_info l_ctl_info = {0};
 
     // Copy utun control name
     if (::strlcpy(l_ctl_info.ctl_name, UTUN_CONTROL_NAME, sizeof(l_ctl_info.ctl_name))
-            >= sizeof(l_ctl_info.ctl_name)){
-        emit error( QString("UTUN_CONTROL_NAME % is too long").arg(UTUN_CONTROL_NAME));
+        >= sizeof(l_ctl_info.ctl_name)) {
+        emit error(QString("UTUN_CONTROL_NAME %1 is too long").arg(UTUN_CONTROL_NAME));
         return;
     }
 
     // Create utun socket
     int l_tun_fd = ::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
-    if( l_tun_fd < 0){
-        int l_errno = errno;
-        char l_errbuf[256];
-        ::strerror_r(l_errno, l_errbuf,sizeof(l_errbuf));
-        emit error ( QString("Opening utun device control (SYSPROTO_CONTROL) error: '%1' (code %2)").arg(l_errbuf).arg(l_errno));
+    if (l_tun_fd < 0) {
+        emit error(QString("Opening utun device control (SYSPROTO_CONTROL) error: %1")
+                       .arg(getErrorString()));
         return;
     }
     qInfo() << "Utun SYSPROTO_CONTROL descriptor obtained";
 
-    // Pass control structure to the utun socket
-    if( ::ioctl(l_tun_fd, CTLIOCGINFO, &l_ctl_info ) < 0 ){
-        int l_errno = errno;
-        char l_errbuf[256];
-        ::strerror_r(l_errno, l_errbuf,sizeof(l_errbuf));
-        emit error (QString("Can't execute ioctl(CTLIOCGINFO): '%1' (code %1)").arg(l_errbuf).arg(l_errno));
+    // Retrieve control ID via ioctl
+    if (::ioctl(l_tun_fd, CTLIOCGINFO, &l_ctl_info) < 0) {
+        ::close(l_tun_fd);
+        emit error(QString("Can't execute ioctl(CTLIOCGINFO): %1").arg(getErrorString()));
         return;
     }
     qInfo() << "Utun CTLIOCGINFO structure passed through ioctl";
 
     // Trying to connect with one of utunX devices
     int l_ret = -1;
-    for(int l_unit = 0; l_unit < 256; l_unit++){
+    for (int l_unit = 0; l_unit < 256; l_unit++) {
         struct sockaddr_ctl l_sa_ctl = {0};
         l_sa_ctl.sc_id = l_ctl_info.ctl_id;
         l_sa_ctl.sc_len = sizeof(l_sa_ctl);
@@ -122,234 +126,323 @@ void DapUtun::tunDeviceCreate()
         l_sa_ctl.ss_sysaddr = AF_SYS_CONTROL;
         l_sa_ctl.sc_unit = l_unit + 1;
 
-        // If connect successful, new utunX device should be created
-        l_ret = ::connect(l_tun_fd, (struct sockaddr *)&l_sa_ctl, sizeof(l_sa_ctl));
-        if(l_ret == 0)
+        l_ret = ::connect(l_tun_fd, reinterpret_cast<struct sockaddr*>(&l_sa_ctl), sizeof(l_sa_ctl));
+        if (l_ret == 0)
             break;
     }
-    // Check if the previous step was successful
-    if (l_ret < 0){
-        int l_errno = errno;
-        char l_errbuf[256];
-        ::strerror_r(l_errno, l_errbuf,sizeof(l_errbuf));
-        emit error( QString("Can't create utun device: '%1' (code %2)").arg(l_errbuf).arg(l_errno));
+
+    if (l_ret < 0) {
+        ::close(l_tun_fd);
+        emit error(QString("Can't create utun device: %1").arg(getErrorString()));
         return;
     }
-
     // Get iface name of newly created utun dev.
     qInfo() << "Utun device created";
-    char l_utunname[20];
-    l_utunname[0] = '\0';
+
+    // Retrieve the name of the utun network interface
+    char l_utunname[20] = {0};
     socklen_t l_utunname_len = sizeof(l_utunname);
-    if (::getsockopt(l_tun_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, l_utunname, &l_utunname_len) ){
-        int l_errno = errno;
-        char l_errbuf[256];
-        ::strerror_r(l_errno, l_errbuf,sizeof(l_errbuf));
-        emit error ( QString("Can't get utun device name: '%s' (code %d)").arg(l_errbuf).arg(l_errno));
+    if (::getsockopt(l_tun_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, l_utunname, &l_utunname_len)) {
+        ::close(l_tun_fd);
+        emit error(QString("Can't get utun device name: %1").arg(getErrorString()));
         return;
     }
 
-    m_tunDeviceName = QString::fromLatin1(l_utunname,l_utunname_len-1);
-    qInfo() << "Created utun "<<m_tunDeviceName<<" network interface";
     
     /* this is the special file descriptor that the caller will use to talk
     * with the virtual interface */
+    m_tunDeviceName = QString::fromLatin1(l_utunname, l_utunname_len - 1);
+    qInfo() << "Created utun" << m_tunDeviceName << "network interface";
+
     m_tunSocket = l_tun_fd;
 }
 
-/**
- * @brief Detects active interface by default routing to 8.8.8.8
- * @return  Returns current active internet interface
- */
 QString DapUtun::getInternetInterface()
 {
     return DapUtils::shellCmd("route get 8.8.8.8 | grep interface | awk '{print $2;}'");
 }
+void DapUtun::saveCurrentConnectionInterfaceData() {
+    m_lastUsedConnectionDevice = getInternetInterface();
+    qDebug() << "Current internet interface:" << m_lastUsedConnectionDevice;
 
-/**
- * @brief DapUtun::saveCurrentConnectionInterfaceData
- */
-void DapUtun::saveCurrentConnectionInterfaceData()
-{
-
-    m_lastUsedConnectionDevice = this->getInternetInterface();
-    qDebug() << "Current internet interface "<< m_lastUsedConnectionDevice;
-    QString result = DapUtils::shellCmd(QString("networksetup -listnetworkserviceorder | grep 'Hardware Port' | grep %1").arg(m_lastUsedConnectionDevice));
-
-    QStringList res1 = result.split(":"); // Break down answer by Hardware port: and Device
+    QString cmdList = QString("networksetup -listnetworkserviceorder | grep 'Hardware Port' | grep %1")
+                          .arg(m_lastUsedConnectionDevice);
+    QString result = DapUtils::shellCmd(cmdList);
 
-    if(res1.length() < 3) {
-        qWarning() << "Can't get current connection interface name! Command returns "<< result;
+    QStringList parts = result.split(":");
+    if (parts.length() < 3) {
+        qWarning() << "Unable to retrieve connection interface name! Command output:" << result;
         return;
     }
 
-    QStringList res2 = res1[1].split(","); // Split from ,Device
-
-    if(res2.length() < 2) {
-        qWarning() << " Wrong networksetup answer! Command returns "<< result;
+    QStringList interfaceParts = parts[1].split(",");
+    if (interfaceParts.length() < 2) {
+        qWarning() << "Unexpected format from networksetup command! Command output:" << result;
         return;
     }
 
-    m_lastUsedConnectionName = res2[0].trimmed();
-    qDebug() << "Current internet connection name" << m_lastUsedConnectionName;
+    m_lastUsedConnectionName = interfaceParts[0].trimmed();
+    qDebug() << "Current internet connection name:" << m_lastUsedConnectionName;
 
-    result = DapUtils::shellCmd(QString("networksetup -getinfo \"%1\" | grep Router").arg(m_lastUsedConnectionName));
-    QStringList res3 =result.split("\n", Qt::SkipEmptyParts);
-    if(res3.length() < 1) {
-        qWarning() << "No default router at all";
-    }else{
-        QStringList res4 = res3[0].split(":");
-        if(res3.length() != 2) {
-            qWarning() << "No default route address in line";
-        }else{
-            m_defaultGwOld =  res4[1] == "none" ? QString() : res4[1];
+    QString cmdGetInfo = QString("networksetup -getinfo \"%1\" | grep Router")
+                             .arg(m_lastUsedConnectionName);
+    result = DapUtils::shellCmd(cmdGetInfo);
+
+    QStringList infoLines = result.split("\n", Qt::SkipEmptyParts);
+    if (infoLines.isEmpty()) {
+        qWarning() << "No default router found.";
+    } else {
+        QStringList routerParts = infoLines.first().split(":");
+        if (routerParts.length() != 2) {
+            qWarning() << "Unexpected default router line format:" << infoLines.first();
+        } else {
+            QString routerValue = routerParts[1].trimmed();
+            m_defaultGwOld = (routerValue == "none") ? QString() : routerValue;
         }
     }
 
-    qInfo() << "DeviceName name:" << m_lastUsedConnectionDevice
-             << "Interface Name:" << m_lastUsedConnectionName
-             << "Router" << m_defaultGwOld
-                ;
+    qInfo() << "Device Name:" << m_lastUsedConnectionDevice
+            << "Interface Name:" << m_lastUsedConnectionName
+            << "Router:" << m_defaultGwOld;
+}
+
+QStringList DapUtun::getNetworkServices() {
+    QProcess process;
+    process.start("networksetup", QStringList() << "-listallnetworkservices");
+
+    if (!process.waitForFinished(5000)) {
+        qWarning() << "Failed to get list of network services:" << process.errorString();
+        return QStringList();
+    }
+
+    QStringList lines = QString(process.readAllStandardOutput()).split("\n", Qt::SkipEmptyParts);
 
+    if (lines.size() < 2) {
+        qWarning() << "No valid network services found.";
+        return QStringList();
+    }
+
+    return lines.mid(1);
 }
 
+QString DapUtun::getDNSServers(const QString &service) {
+    QProcess process;
+    process.start("networksetup", QStringList() << "-getdnsservers" << service);
+    if (!process.waitForFinished(5000)) {
+        qWarning() << "Timeout while getting DNS for service" << service << ":" << process.errorString();
+        return QString();
+    }
+
+    return process.readAllStandardOutput().trimmed();
+}
 
-/**
- * @brief DapUtun::onWorkerStarted
- */
-void DapUtun::onWorkerStarted()
-{
-    qDebug() << "tunnelCreate()";
+bool DapUtun::setDNS(const QString &service, const QString &dnsServer) {
     QProcess process;
+    QStringList arguments;
 
-    if(m_tunSocket <= 0) {
-        qCritical() << "Can't bring up network interface";
-        return;
+    if (dnsServer.isEmpty()) {
+        arguments << "-setdnsservers" << service << "empty";
+    } else {
+        arguments << "-setdnsservers" << service << dnsServer;
     }
 
-    saveCurrentConnectionInterfaceData();
+    process.start("networksetup", arguments);
+    if (!process.waitForFinished(5000)) {
+        qWarning() << "Timeout while configuring DNS for service" << service << ":" << process.errorString();
+        return false;
+    }
 
-//    networksetup -ordernetworkservices
+    if (process.exitCode() != 0) {
+        qWarning() << "Command failed for service" << service << "with exit code:" << process.exitCode();
+        qWarning() << "Error output: " << process.readAllStandardError();
+        return false;
+    }
 
-    // Update route table for upstream if it's not local
-    if(!isLocalAddress(upstreamAddress())) {
-        QString run = QString("route add -host %2 %1")
-                          .arg(m_defaultGwOld).arg(upstreamAddress());
-        qDebug() << "Execute " << run;
-        ::system(run.toLatin1().constData());
+    return true;
+}
+
+//Not used because breaks other interfaces. At the moment, only the utun interface is being modified.
+void DapUtun::configureDNS(const QMap<QString, QString> &dnsMap) {
+    QStringList services = getNetworkServices();
+    if (services.isEmpty()) {
+        qWarning() << "No network services detected.";
+        return;
     }
 
-    // Add all CDBs into routing exeption
-    for (const auto &str : m_routingExceptionAddrs){
-        QString run = QString("route add -host %2 %1")
-                          .arg(m_defaultGwOld).arg(str);
-        qDebug() << "Execute " << run;
-        ::system(run.toLatin1().constData() );
+    for (const QString &service : services) {
+        QString dnsServer = dnsMap.value(service, "");
+        if (setDNS(service, dnsServer)) {
+            qDebug() << "DNS servers successfully " << (dnsServer.isEmpty() ? "cleared" : "configured") << " for service:" << service;
+        } else {
+            qWarning() << "Failed to " << (dnsServer.isEmpty() ? "clear" : "configure") << " DNS servers for service:" << service;
+        }
     }
+}
 
+void DapUtun::clearAllDNS() {
+    configureDNS(QMap<QString, QString>());
+}
 
-    // Create connection
-    /*
-    QString cmdConnAdd = QString(
-                "networksetup -createnetworkservice %1 %2 ;"
-                "networksetup -setnetworkserviceenabled %1 on;"
-                "networksetup -setmanual %1 %3 255.255.255.255 %4;"
-                "networksetup -setdnsservers %4"
-                ) .arg (DAP_BRAND)
-                  .arg(tunDeviceName())
-                  .arg(addr())
-                  .arg(gw());
+void DapUtun::onWorkerStarted()
+{
+    qDebug() << "Starting tunnel creation";
 
-    qDebug() << "[Cmd to created interface: " <<  cmdConnAdd;
+    if (m_tunSocket <= 0) {
+        qCritical() << "Failed to bring up network interface: invalid tunnel socket";
+        return;
+    }
 
-    DapTunUnixAbstract::runShellCmd( cmdConnAdd );
+    saveCurrentConnectionInterfaceData();
 
+    m_currentInterface = getCurrentNetworkInterface();
+    if (m_currentInterface.isEmpty()) {
+        qCritical() << "No active network interface found!";
+        return;
+    }
 
-    // Add additional Apple routes
-    QString cmdAddAdditionalRoutes = QString("networksetup -setadditionalroutes %1").arg(DAP_BRAND);
-    foreach(QString additionalRoute, appleAdditionalRoutes){
-        cmdAddAdditionalRoutes += additionalRoute;
-        cmdAddAdditionalRoutes += "\"\"";
+    if (!isLocalAddress(upstreamAddress())) {
+        QString run = QString("route add -host %2 %1")
+                          .arg(m_defaultGwOld)
+                          .arg(upstreamAddress());
+        executeCommand(run);
     }
 
-    DapTunUnixAbstract::runShellCmd( cmdAddAdditionalRoutes);*/
+    for (const auto &address : m_routingExceptionAddrs) {
+        QString run = QString("route add -host %2 %1")
+                          .arg(m_defaultGwOld)
+                          .arg(address);
+        executeCommand(run);
+    }
 
+    // QString cmdConnAdd = QString(
+    //                          "networksetup -createnetworkservice %1 %2 ;"
+    //                          "networksetup -setnetworkserviceenabled %1 on;"
+    //                          "networksetup -setmanual %1 %3 255.255.255.255 %4;"
+    //                          ).arg(DAP_BRAND)
+    //                          .arg(tunDeviceName())
+    //                          .arg(addr())
+    //                          .arg(gw());
 
-    // Bring up network interface
-    ::system(QString("ifconfig %1 %2 %3")
-                 .arg(tunDeviceName()).arg(addr()).arg(gw()).toLatin1().constData());
+    // qDebug() << "Network service creation command:" << cmdConnAdd;
+    // DapUtils::shellCmd(cmdConnAdd);
 
-    qDebug() << "Configured " << tunDeviceName() << " with " << addr() << "-->" << gw();
+    QString cmdSetDNS = QString("networksetup -setdnsservers %1 %2")
+                            .arg(m_currentInterface)
+                            .arg(gw());
 
-    // Remove old default route
-    ::system(QString("route delete default").toLatin1().constData());
+    qDebug() << "Setting DNS for" << m_currentInterface << "to:" << gw();
+    DapUtils::shellCmd(cmdSetDNS);
 
-    qDebug() << "Removed default route " << m_defaultGwOld;
+    QString ifconfigCmd = QString("ifconfig %1 %2 %3")
+                              .arg(tunDeviceName())
+                              .arg(addr())
+                              .arg(gw());
+    executeCommand(ifconfigCmd);
+    qDebug() << "Configured interface" << tunDeviceName() << "with IP" << addr() << "and gateway" << gw();
+
+    executeCommand("route delete default");
+    qDebug() << "Removed default route:" << m_defaultGwOld;
 
-    // Setup default route
     QString gateway = gw();
     qDebug() << "Gateway obtained: " << gateway;
     if (!gateway.isEmpty()) {
-        ::system(QString("route add default %1").arg(gateway).toLatin1().constData());
-        qDebug() << "Added default route " << gateway;
+        executeCommand(QString("route add default %1").arg(gateway));
+        qDebug() << "Added default route:" << gateway;
 
-        ::system(QString("route add -net 224.0.0.0/4 %1").arg(gateway).toLatin1().constData());
-        qDebug() << "Added multicast route " << gateway;
+        executeCommand(QString("route add -net 224.0.0.0/4 %1").arg(gateway));
+        qDebug() << "Added multicast route via gateway:" << gateway;
 
-        ::system(QString("route add -net 255.255.255.255/32 %1").arg(gateway).toLatin1().constData());
-        qDebug() << "Added broadcast route " << gateway;
+        executeCommand(QString("route add -net 255.255.255.255/32 %1").arg(gateway));
+        qDebug() << "Added broadcast route via gateway:" << gateway;
     } else {
-        qWarning() << "Gateway is empty!";
+        qWarning() << "Gateway is empty, cannot set up default routes";
     }
 
-    // Add additional Apple routes
-    foreach(QString additionalRoute, appleAdditionalRoutes) {
-        QStringList routeArgs = additionalRoute.split(QRegExp("\\s+"), Qt::SkipEmptyParts);
-
-        if(routeArgs.length() == 1) {
-            ::system(QString("route add -host %1 %2")
-                         .arg(routeArgs[0]).arg(gw()).toLatin1().constData());
-            qDebug() << "Added host route " << routeArgs[0] << " via " << gw();
-        } else if (routeArgs.length() == 2) {
-            ::system(QString("route add -net %1 %2 %3")
-                         .arg(routeArgs[0]).arg(routeArgs[1]).arg(gw()).toLatin1().constData());
-            qDebug() << "Added network route " << routeArgs[0] << "/" << routeArgs[1] << " via " << gw();
-        } else {
-            qWarning() << "Unparseable additional route line " << additionalRoute;
-        }
+    QString cmdAddAdditionalRoutes = QString("networksetup -setadditionalroutes %1").arg(DAP_BRAND);
+    foreach (const QString &additionalRoute, appleAdditionalRoutes) {
+        cmdAddAdditionalRoutes += " " + additionalRoute;
     }
+    qDebug() << "Additional Apple routes command:" << cmdAddAdditionalRoutes;
+    DapUtils::shellCmd(cmdAddAdditionalRoutes);
 
     m_isCreated = true;
     emit created();
 }
 
+QString DapUtun::getCurrentNetworkInterface()
+{
+    qDebug() << "Fetching current active network interface...";
+
+    QProcess routeProcess;
+    routeProcess.start("route get default");
+    routeProcess.waitForFinished();
+    QString routeOutput = routeProcess.readAllStandardOutput();
+
+    qDebug() << "Raw route get default output:" << routeOutput;
+
+    QString activeInterface;
+    QStringList routeLines = routeOutput.split("\n");
+    for (const QString &line : routeLines) {
+        if (line.contains("interface:")) {
+            activeInterface = line.split(":").last().trimmed();
+            qDebug() << "Detected active interface:" << activeInterface;
+            break;
+        }
+    }
+
+    if (activeInterface.isEmpty()) {
+        qWarning() << "No active internet interface found!";
+        return QString();
+    }
+
+    QProcess serviceOrderProcess;
+    serviceOrderProcess.start("networksetup -listnetworkserviceorder");
+    serviceOrderProcess.waitForFinished();
+    QString serviceOrderOutput = serviceOrderProcess.readAllStandardOutput();
+
+    qDebug() << "Raw network service order output:" << serviceOrderOutput;
+
+    QString regexPattern = R"(\(Hardware Port: (.+?), Device: )" + QRegularExpression::escape(activeInterface) + R"(\))";
+    QRegularExpression regex(regexPattern);
+    QRegularExpressionMatch match = regex.match(serviceOrderOutput);
+
+    if (match.hasMatch()) {
+        QString matchedService = match.captured(1).trimmed();
+        qDebug() << "Matched active network service via service order:" << matchedService;
+        return matchedService;
+    }
+
+    qWarning() << "Could not match active interface to a network service!";
+    return QString();
+}
 
-/**
- * @brief DapUtun::onWorkerStopped
- */
 void DapUtun::tunDeviceDestroy()
 {
     DapTunUnixAbstract::tunDeviceDestroy();
-    // Delete upstream routes
-    if(!isLocalAddress(upstreamAddress()))
-    {
-        QString run = QString("route delete -host %1")
-                .arg(upstreamAddress()) ;
-        qDebug() << "Execute "<<run;
-        ::system( run.toLatin1().constData() );
+
+    if (!isLocalAddress(upstreamAddress())){
+        QString cmdDeleteUpstream = QString("route delete -host %1")
+                                        .arg(upstreamAddress());
+        executeCommand(cmdDeleteUpstream);
     }
 
-    for (const auto &str : m_routingExceptionAddrs){
-        QString run = QString("route delete -host %1")
-                          .arg(str);
-        qDebug() << "Execute " << run;
-        ::system(run.toLatin1().constData() );
+    for (const auto &route : m_routingExceptionAddrs) {
+        QString cmdDeleteException = QString("route delete -host %1")
+                                         .arg(route);
+        executeCommand(cmdDeleteException);
     }
 
     // Other routes connected with tunnel should be destroyed autimaticly
 
     // Restore default gateway
-    ::system ( QString("route add default %1").arg(m_defaultGwOld).toLatin1().constData());
-    qInfo() << "Restored default route "<< m_defaultGwOld;
+    QString cmdRestoreDefault = QString("route add default %1")
+                                    .arg(m_defaultGwOld);
+    executeCommand(cmdRestoreDefault);
+    qInfo() << "Restored default route:" << m_defaultGwOld;
+
+    QString cmdRestoreDNS = QString("networksetup -setdnsservers \"%1\" %2")
+                                .arg(m_currentInterface)
+                                .arg(m_defaultGwOld);
+    executeCommand(cmdRestoreDNS);
+    qInfo() << "Restored DNS settings for" << m_currentInterface << "to" << m_defaultGwOld;
 }
-
diff --git a/vpn/client/darwin/DapUtun.h b/vpn/client/darwin/DapUtun.h
index 22cde280f2cd6557261ea096560b6c803af4deb6..1659a4fc29422515060a3f16d2d9875b4af0cfe9 100644
--- a/vpn/client/darwin/DapUtun.h
+++ b/vpn/client/darwin/DapUtun.h
@@ -20,7 +20,28 @@ This file is part of DAP UI SDK the open source project
    You should have received a copy of the GNU General Public License
    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 */
+
 #pragma once
+
+#include <QtDebug>
+#include <QProcess>
+#include <QFile>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sys_domain.h>
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "DapTunUnixAbstract.h"
+#include "DapTunWorkerUnix.h"
+#include "DapNetworkMonitor.h"
+#include "SigUnixHandler.h"
 #include "DapTunUnixAbstract.h"
 
 class DapUtun : public DapTunUnixAbstract
@@ -29,9 +50,14 @@ public:
     DapUtun();
     ~DapUtun() {}
 protected:
+    void executeCommand(const QString &cmd);
     void tunDeviceCreate();
     void tunDeviceDestroy();
     void onWorkerStarted();
+    void clearAllDNS();
+    void configureDNS(const QMap<QString, QString> &dnsMap);
+    QString getCurrentNetworkInterface();
+
 
     // Getting currently using connection interface name from nmcli command-line tool
     // and save to m_lastUsedConnectionName and m_lastUsedConnectionDevice
@@ -39,14 +65,23 @@ protected:
 
 private:
 
+    QStringList getNetworkServices();
+    QString getDNSServers(const QString &service);
+    bool setDNS(const QString &service, const QString &dnsServer);
+
     // Connection witch used before creating utun Interface
     QString m_lastUsedConnectionName;
     QString m_lastUsedConnectionDevice;
 
+    QString m_currentInterface;
+
     QStringList appleAdditionalRoutes; // List of Apple addresses needed to be routed directly through the tunnel
 
-    QString runShellCmd(const QString& cmd);
+    // QString runShellCmd(const QString& cmd);
 
     // Get current active internet interface
     QString getInternetInterface();
+
+    QMap<QString, QString> m_dnsMap;
+
 };
diff --git a/vpn/qml/handlers/DapCmdConnect.cpp b/vpn/qml/handlers/DapCmdConnect.cpp
index 3da24dc601341b1e1837ad77be67e2770df27406..56aabea35e365fb5b87a3d7bce32824ed16cfb27 100644
--- a/vpn/qml/handlers/DapCmdConnect.cpp
+++ b/vpn/qml/handlers/DapCmdConnect.cpp
@@ -7,7 +7,8 @@ DapCmdConnect::DapCmdConnect(QObject *parent)
 }
 
 void DapCmdConnect::sendCmdConnect(const QString& a_addr, quint16 a_port,
-                                   const QString& a_user, const QString& a_pswd,  const QString& a_serial, const bool a_updateRouteTable)
+                                   const QString& a_user, const QString& a_pswd,  const QString& a_serial, const bool a_updateRouteTable,
+                                   const QString& a_runScriptPath, const bool a_runAfterConnect)
 {
     QJsonObject obj;
     obj["action"] = "Connect";
@@ -20,7 +21,10 @@ void DapCmdConnect::sendCmdConnect(const QString& a_addr, quint16 a_port,
         obj["password"] = a_pswd;
     if ( !a_serial.isEmpty() )
         obj["serial"] = QString(a_serial).remove('-');
-    obj["port"] = a_port;
+    if ( !a_runScriptPath.isEmpty() ) {
+        obj["run_script_path"] = QString(a_runScriptPath);
+        obj["run_script_after_connect"] = a_runAfterConnect;
+    }
 
     sendCmd(&obj);
 }
diff --git a/vpn/qml/handlers/DapCmdConnect.h b/vpn/qml/handlers/DapCmdConnect.h
index 552bd94a6c1a0117df1e0dc04022c34379d2f764..aa873fea639f887296ac2fa893377703e070577d 100644
--- a/vpn/qml/handlers/DapCmdConnect.h
+++ b/vpn/qml/handlers/DapCmdConnect.h
@@ -11,8 +11,9 @@ public:
     explicit DapCmdConnect(QObject *parent = nullptr);
 
 public slots:
-    void sendCmdConnect(const QString& a_addr, quint16 a_port,
-                        const QString& a_user= QString(), const QString& a_pswd = QString(),  const QString& a_serial= QString(), const bool a_updateRouteTable = true);
+    void sendCmdConnect(const QString& a_addr, quint16 a_port, const QString& a_user = QString(), const QString& a_pswd = QString(),
+                        const QString& a_serial = QString(), const bool a_updateRouteTable = true,
+                        const QString& a_runScriptPath = QString(), const bool a_runAfterConnect = false);
     void sendCmdConnectByOrder(const QString& a_addr);