diff --git a/luci-app-bandix/Makefile b/luci-app-bandix/Makefile
index dad79ab..55a203e 100644
--- a/luci-app-bandix/Makefile
+++ b/luci-app-bandix/Makefile
@@ -10,7 +10,7 @@ LUCI_DEPENDS:=+luci-base +luci-lib-jsonc +curl +bandix
PKG_MAINTAINER:=timsaya
-PKG_VERSION:=0.6.3
+PKG_VERSION:=0.8.0
PKG_RELEASE:=1
include $(TOPDIR)/feeds/luci/luci.mk
diff --git a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/dns.js b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/dns.js
new file mode 100644
index 0000000..1b81dfc
--- /dev/null
+++ b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/dns.js
@@ -0,0 +1,1524 @@
+'use strict';
+'require view';
+'require ui';
+'require uci';
+'require rpc';
+'require poll';
+
+const translations = {
+ 'zh-cn': {
+ 'Bandix DNS 监控': 'Bandix DNS 监控',
+ '正在加载数据...': '正在加载数据...',
+ '无法获取数据': '无法获取数据',
+ 'DNS 监控': 'DNS 监控',
+ 'DNS 查询记录': 'DNS 查询记录',
+ 'DNS 统计信息': 'DNS 统计信息',
+ 'DNS监控未启用': 'DNS监控未启用',
+ '请在设置中启用DNS监控功能': '请在设置中启用DNS监控功能',
+ '前往设置': '前往设置',
+ '无数据': '无数据',
+ '时间': '时间',
+ '域名': '域名',
+ '查询类型': '查询类型',
+ '类型': '类型',
+ '响应码': '响应码',
+ '响应时间': '响应时间',
+ '源IP': '源IP',
+ '目标IP': '目标IP',
+ '设备': '设备',
+ '响应IP': '响应IP',
+ '响应结果': '响应结果',
+ 'DNS服务器': 'DNS服务器',
+ '查询': '查询',
+ '响应': '响应',
+ '过滤': '过滤',
+ '域名过滤': '域名过滤',
+ '设备过滤': '设备过滤',
+ 'DNS服务器过滤': 'DNS服务器过滤',
+ '类型过滤': '类型过滤',
+ '全部': '全部',
+ '仅查询': '仅查询',
+ '仅响应': '仅响应',
+ '搜索': '搜索',
+ '搜索域名': '搜索域名',
+ '搜索设备': '搜索设备',
+ '搜索DNS服务器': '搜索DNS服务器',
+ '清除': '清除',
+ '上一页': '上一页',
+ '下一页': '下一页',
+ '第': '第',
+ '页,共': '页,共',
+ '共': '共',
+ '条记录': '条记录',
+ '每页显示': '每页显示',
+ '条': '条',
+ '总查询数': '总查询数',
+ '总响应数': '总响应数',
+ '有响应查询': '有响应查询',
+ '无响应查询': '无响应查询',
+ '平均响应时间': '平均响应时间',
+ '最快响应时间': '最快响应时间',
+ '最慢响应时间': '最慢响应时间',
+ '响应时间': '响应时间',
+ '成功率': '成功率',
+ '成功': '成功',
+ '失败': '失败',
+ '最常查询域名': '最常查询域名',
+ '最常用查询类型': '最常用查询类型',
+ '最活跃设备': '最活跃设备',
+ '最常用DNS服务器': '最常用DNS服务器',
+ '唯一设备数': '唯一设备数',
+ '时间范围': '时间范围',
+ '毫秒': '毫秒',
+ '分钟': '分钟',
+ '刷新': '刷新',
+ '未知设备': '未知设备',
+ '成功': '成功',
+ '域名未找到': '域名未找到',
+ '服务器错误': '服务器错误',
+ '格式错误': '格式错误',
+ '拒绝': '拒绝',
+ '其他': '其他'
+ },
+ 'zh-tw': {
+ 'Bandix DNS 监控': 'Bandix DNS 監控',
+ '正在加载数据...': '正在載入資料...',
+ '无法获取数据': '無法獲取資料',
+ 'DNS 监控': 'DNS 監控',
+ 'DNS 查询记录': 'DNS 查詢記錄',
+ 'DNS 统计信息': 'DNS 統計資訊',
+ 'DNS监控未启用': 'DNS監控未啟用',
+ '请在设置中启用DNS监控功能': '請在設置中啟用DNS監控功能',
+ '前往设置': '前往設置',
+ '无数据': '無數據',
+ '时间': '時間',
+ '域名': '域名',
+ '查询类型': '查詢類型',
+ '类型': '類型',
+ '响应码': '響應碼',
+ '响应时间': '響應時間',
+ '源IP': '源IP',
+ '目标IP': '目標IP',
+ '设备': '設備',
+ '响应IP': '響應IP',
+ '响应结果': '響應結果',
+ 'DNS服务器': 'DNS伺服器',
+ '查询': '查詢',
+ '响应': '響應',
+ '过滤': '過濾',
+ '域名过滤': '域名過濾',
+ '设备过滤': '設備過濾',
+ 'DNS服务器过滤': 'DNS伺服器過濾',
+ '类型过滤': '類型過濾',
+ '全部': '全部',
+ '仅查询': '僅查詢',
+ '仅响应': '僅響應',
+ '搜索': '搜尋',
+ '搜索域名': '搜尋域名',
+ '搜索设备': '搜尋設備',
+ '搜索DNS服务器': '搜尋DNS伺服器',
+ '清除': '清除',
+ '上一页': '上一頁',
+ '下一页': '下一頁',
+ '第': '第',
+ '页,共': '頁,共',
+ '共': '共',
+ '条记录': '條記錄',
+ '每页显示': '每頁顯示',
+ '条': '條',
+ '总查询数': '總查詢數',
+ '总响应数': '總響應數',
+ '有响应查询': '有響應查詢',
+ '无响应查询': '無響應查詢',
+ '平均响应时间': '平均響應時間',
+ '最快响应时间': '最快響應時間',
+ '最慢响应时间': '最慢響應時間',
+ '响应时间': '響應時間',
+ '成功率': '成功率',
+ '成功': '成功',
+ '失败': '失敗',
+ '最常查询域名': '最常查詢域名',
+ '最常用查询类型': '最常用查詢類型',
+ '最活跃设备': '最活躍設備',
+ '最常用DNS服务器': '最常用DNS伺服器',
+ '唯一设备数': '唯一設備數',
+ '时间范围': '時間範圍',
+ '毫秒': '毫秒',
+ '分钟': '分鐘',
+ '刷新': '重新整理',
+ '未知设备': '未知設備',
+ '成功': '成功',
+ '域名未找到': '域名未找到',
+ '服务器错误': '伺服器錯誤',
+ '格式错误': '格式錯誤',
+ '拒绝': '拒絕',
+ '其他': '其他'
+ },
+ 'en': {
+ 'Bandix DNS 监控': 'Bandix DNS Monitor',
+ '正在加载数据...': 'Loading data...',
+ '无法获取数据': 'Unable to fetch data',
+ 'DNS 监控': 'DNS Monitor',
+ 'DNS 查询记录': 'DNS Query Records',
+ 'DNS 统计信息': 'DNS Statistics',
+ 'DNS监控未启用': 'DNS Monitoring Disabled',
+ '请在设置中启用DNS监控功能': 'Please enable DNS monitoring in settings',
+ '前往设置': 'Go to Settings',
+ '无数据': 'No Data',
+ '时间': 'Time',
+ '域名': 'Domain',
+ '查询类型': 'Query Type',
+ '类型': 'Type',
+ '响应码': 'Response Code',
+ '响应时间': 'Response Time',
+ '源IP': 'Source IP',
+ '目标IP': 'Destination IP',
+ '设备': 'Device',
+ '响应IP': 'Response IPs',
+ '响应结果': 'Response Result',
+ 'DNS服务器': 'DNS Server',
+ '查询': 'Query',
+ '响应': 'Response',
+ '过滤': 'Filter',
+ '域名过滤': 'Domain Filter',
+ '设备过滤': 'Device Filter',
+ 'DNS服务器过滤': 'DNS Server Filter',
+ '类型过滤': 'Type Filter',
+ '全部': 'All',
+ '仅查询': 'Queries Only',
+ '仅响应': 'Responses Only',
+ '搜索': 'Search',
+ '搜索域名': 'Search Domain',
+ '搜索设备': 'Search Device',
+ '搜索DNS服务器': 'Search DNS Server',
+ '清除': 'Clear',
+ '上一页': 'Previous',
+ '下一页': 'Next',
+ '第': 'Page',
+ '页,共': 'of',
+ '共': 'Total',
+ '条记录': 'records',
+ '每页显示': 'Per Page',
+ '条': '',
+ '总查询数': 'Total Queries',
+ '总响应数': 'Total Responses',
+ '有响应查询': 'Queries with Response',
+ '无响应查询': 'Queries without Response',
+ '平均响应时间': 'Avg Response Time',
+ '最快响应时间': 'Min Response Time',
+ '最慢响应时间': 'Max Response Time',
+ '响应时间': 'Response Time',
+ '成功率': 'Success Rate',
+ '成功': 'Success',
+ '失败': 'Failure',
+ '最常查询域名': 'Top Domains',
+ '最常用查询类型': 'Top Query Types',
+ '最活跃设备': 'Top Devices',
+ '最常用DNS服务器': 'Top DNS Servers',
+ '唯一设备数': 'Unique Devices',
+ '时间范围': 'Time Range',
+ '毫秒': 'ms',
+ '分钟': 'minutes',
+ '刷新': 'Refresh',
+ '未知设备': 'Unknown Device',
+ '成功': 'Success',
+ '域名未找到': 'Domain not found',
+ '服务器错误': 'Server error',
+ '格式错误': 'Format error',
+ '拒绝': 'Refused',
+ '其他': 'Other'
+ },
+ 'fr': {
+ 'Bandix DNS 监控': 'Bandix Surveillance DNS',
+ '正在加载数据...': 'Chargement des données...',
+ '无法获取数据': 'Impossible de récupérer les données',
+ 'DNS 监控': 'Surveillance DNS',
+ 'DNS 查询记录': 'Enregistrements de Requêtes DNS',
+ 'DNS 统计信息': 'Statistiques DNS',
+ 'DNS监控未启用': 'Surveillance DNS désactivée',
+ '请在设置中启用DNS监控功能': 'Veuillez activer la surveillance DNS dans les paramètres',
+ '前往设置': 'Aller aux Paramètres',
+ '无数据': 'Aucune Donnée',
+ '时间': 'Heure',
+ '域名': 'Domaine',
+ '查询类型': 'Type de Requête',
+ '类型': 'Type',
+ '响应码': 'Code de Réponse',
+ '响应时间': 'Temps de Réponse',
+ '源IP': 'IP Source',
+ '目标IP': 'IP de Destination',
+ '设备': 'Appareil',
+ '响应IP': 'IPs de Réponse',
+ '响应结果': 'Résultat de Réponse',
+ 'DNS服务器': 'Serveur DNS',
+ '查询': 'Requête',
+ '响应': 'Réponse',
+ '过滤': 'Filtre',
+ '域名过滤': 'Filtre de Domaine',
+ '设备过滤': 'Filtre d\'Appareil',
+ 'DNS服务器过滤': 'Filtre de Serveur DNS',
+ '类型过滤': 'Filtre de Type',
+ '全部': 'Tous',
+ '仅查询': 'Requêtes Seulement',
+ '仅响应': 'Réponses Seulement',
+ '搜索': 'Rechercher',
+ '搜索域名': 'Rechercher un Domaine',
+ '搜索设备': 'Rechercher un Appareil',
+ '搜索DNS服务器': 'Rechercher un Serveur DNS',
+ '清除': 'Effacer',
+ '上一页': 'Précédent',
+ '下一页': 'Suivant',
+ '第': 'Page',
+ '页,共': 'sur',
+ '共': 'Total',
+ '条记录': 'enregistrements',
+ '每页显示': 'Par Page',
+ '条': '',
+ '总查询数': 'Total des Requêtes',
+ '总响应数': 'Total des Réponses',
+ '有响应查询': 'Requêtes avec Réponse',
+ '无响应查询': 'Requêtes sans Réponse',
+ '平均响应时间': 'Temps de Réponse Moyen',
+ '最快响应时间': 'Temps de Réponse Minimum',
+ '最慢响应时间': 'Temps de Réponse Maximum',
+ '响应时间': 'Temps de Réponse',
+ '成功率': 'Taux de Réussite',
+ '成功': 'Succès',
+ '失败': 'Échec',
+ '最常查询域名': 'Domaines les Plus Consultés',
+ '最常用查询类型': 'Types de Requêtes les Plus Utilisés',
+ '最活跃设备': 'Appareils les Plus Actifs',
+ '最常用DNS服务器': 'Serveurs DNS les Plus Utilisés',
+ '唯一设备数': 'Appareils Uniques',
+ '时间范围': 'Plage de Temps',
+ '毫秒': 'ms',
+ '分钟': 'minutes',
+ '刷新': 'Actualiser',
+ '未知设备': 'Appareil Inconnu',
+ '成功': 'Succès',
+ '域名未找到': 'Domaine introuvable',
+ '服务器错误': 'Erreur serveur',
+ '格式错误': 'Erreur de format',
+ '拒绝': 'Refusé',
+ '其他': 'Autre'
+ },
+ 'ja': {
+ 'Bandix DNS 监控': 'Bandix DNS監視',
+ '正在加载数据...': 'データを読み込み中...',
+ '无法获取数据': 'データを取得できません',
+ 'DNS 监控': 'DNS監視',
+ 'DNS 查询记录': 'DNSクエリ記録',
+ 'DNS 统计信息': 'DNS統計情報',
+ 'DNS监控未启用': 'DNS監視が無効です',
+ '请在设置中启用DNS监控功能': '設定でDNS監視機能を有効にしてください',
+ '前往设置': '設定へ',
+ '无数据': 'データなし',
+ '时间': '時刻',
+ '域名': 'ドメイン',
+ '查询类型': 'クエリタイプ',
+ '类型': 'タイプ',
+ '响应码': '応答コード',
+ '响应时间': '応答時間',
+ '源IP': '送信元IP',
+ '目标IP': '宛先IP',
+ '设备': 'デバイス',
+ '响应IP': '応答IP',
+ '响应结果': '応答結果',
+ 'DNS服务器': 'DNSサーバー',
+ '查询': 'クエリ',
+ '响应': '応答',
+ '过滤': 'フィルター',
+ '域名过滤': 'ドメインフィルター',
+ '设备过滤': 'デバイスフィルター',
+ 'DNS服务器过滤': 'DNSサーバーフィルター',
+ '类型过滤': 'タイプフィルター',
+ '全部': 'すべて',
+ '仅查询': 'クエリのみ',
+ '仅响应': '応答のみ',
+ '搜索': '検索',
+ '搜索域名': 'ドメインを検索',
+ '搜索设备': 'デバイスを検索',
+ '搜索DNS服务器': 'DNSサーバーを検索',
+ '清除': 'クリア',
+ '上一页': '前へ',
+ '下一页': '次へ',
+ '第': 'ページ',
+ '页,共': '/',
+ '共': '合計',
+ '条记录': '件の記録',
+ '每页显示': 'ページあたり',
+ '条': '',
+ '总查询数': '総クエリ数',
+ '总响应数': '総応答数',
+ '有响应查询': '応答ありのクエリ',
+ '无响应查询': '応答なしのクエリ',
+ '平均响应时间': '平均応答時間',
+ '最快响应时间': '最小応答時間',
+ '最慢响应时间': '最大応答時間',
+ '响应时间': '応答時間',
+ '成功率': '成功率',
+ '成功': '成功',
+ '失败': '失敗',
+ '最常查询域名': '最も頻繁にクエリされるドメイン',
+ '最常用查询类型': '最も使用されるクエリタイプ',
+ '最活跃设备': '最もアクティブなデバイス',
+ '最常用DNS服务器': '最も使用されるDNSサーバー',
+ '唯一设备数': 'ユニークデバイス数',
+ '时间范围': '時間範囲',
+ '毫秒': 'ミリ秒',
+ '分钟': '分',
+ '刷新': '更新',
+ '未知设备': '不明なデバイス',
+ '成功': '成功',
+ '域名未找到': 'ドメインが見つかりません',
+ '服务器错误': 'サーバーエラー',
+ '格式错误': 'フォーマットエラー',
+ '拒绝': '拒否',
+ '其他': 'その他'
+ },
+ 'ru': {
+ 'Bandix DNS 监控': 'Bandix Мониторинг DNS',
+ '正在加载数据...': 'Загрузка данных...',
+ '无法获取数据': 'Не удалось получить данные',
+ 'DNS 监控': 'Мониторинг DNS',
+ 'DNS 查询记录': 'Записи DNS-запросов',
+ 'DNS 统计信息': 'Статистика DNS',
+ 'DNS监控未启用': 'Мониторинг DNS отключен',
+ '请在设置中启用DNS监控功能': 'Пожалуйста, включите мониторинг DNS в настройках',
+ '前往设置': 'Перейти в Настройки',
+ '无数据': 'Нет Данных',
+ '时间': 'Время',
+ '域名': 'Домен',
+ '查询类型': 'Тип Запроса',
+ '类型': 'Тип',
+ '响应码': 'Код Ответа',
+ '响应时间': 'Время Ответа',
+ '源IP': 'Исходный IP',
+ '目标IP': 'IP Назначения',
+ '设备': 'Устройство',
+ '响应IP': 'IP Ответов',
+ '响应结果': 'Результат Ответа',
+ 'DNS服务器': 'DNS Сервер',
+ '查询': 'Запрос',
+ '响应': 'Ответ',
+ '过滤': 'Фильтр',
+ '域名过滤': 'Фильтр Домена',
+ '设备过滤': 'Фильтр Устройства',
+ 'DNS服务器过滤': 'Фильтр DNS Сервера',
+ '类型过滤': 'Фильтр Типа',
+ '全部': 'Все',
+ '仅查询': 'Только Запросы',
+ '仅响应': 'Только Ответы',
+ '搜索': 'Поиск',
+ '搜索域名': 'Поиск Домена',
+ '搜索设备': 'Поиск Устройства',
+ '搜索DNS服务器': 'Поиск DNS Сервера',
+ '清除': 'Очистить',
+ '上一页': 'Предыдущая',
+ '下一页': 'Следующая',
+ '第': 'Страница',
+ '页,共': 'из',
+ '共': 'Всего',
+ '条记录': 'записей',
+ '每页显示': 'На Странице',
+ '条': '',
+ '总查询数': 'Всего Запросов',
+ '总响应数': 'Всего Ответов',
+ '有响应查询': 'Запросы с Ответом',
+ '无响应查询': 'Запросы без Ответа',
+ '平均响应时间': 'Среднее Время Ответа',
+ '最快响应时间': 'Минимальное Время Ответа',
+ '最慢响应时间': 'Максимальное Время Ответа',
+ '响应时间': 'Время Ответа',
+ '成功率': 'Процент Успеха',
+ '成功': 'Успех',
+ '失败': 'Неудача',
+ '最常查询域名': 'Наиболее Запрашиваемые Домены',
+ '最常用查询类型': 'Наиболее Используемые Типы Запросов',
+ '最活跃设备': 'Наиболее Активные Устройства',
+ '最常用DNS服务器': 'Наиболее Используемые DNS Серверы',
+ '唯一设备数': 'Уникальных Устройств',
+ '时间范围': 'Временной Диапазон',
+ '毫秒': 'мс',
+ '分钟': 'минут',
+ '刷新': 'Обновить',
+ '未知设备': 'Неизвестное Устройство',
+ '成功': 'Успех',
+ '域名未找到': 'Домен не найден',
+ '服务器错误': 'Ошибка сервера',
+ '格式错误': 'Ошибка формата',
+ '拒绝': 'Отклонено',
+ '其他': 'Другое'
+ }
+};
+
+function getTranslation(key, language) {
+ return translations[language]?.[key] || key;
+}
+
+function getSystemLanguage() {
+ var luciLang = uci.get('luci', 'main', 'lang');
+ if (luciLang && translations[luciLang]) {
+ return luciLang;
+ }
+ var systemLang = document.documentElement.lang || 'en';
+ if (translations[systemLang]) {
+ return systemLang;
+ }
+ return 'en';
+}
+
+function isDarkMode() {
+ var userTheme = uci.get('bandix', 'general', 'theme');
+ if (userTheme) {
+ if (userTheme === 'dark') {
+ return true;
+ } else if (userTheme === 'light') {
+ return false;
+ }
+ }
+
+ var mediaUrlBase = uci.get('luci', 'main', 'mediaurlbase');
+ if (mediaUrlBase && mediaUrlBase.toLowerCase().includes('dark')) {
+ return true;
+ }
+
+ if (mediaUrlBase && mediaUrlBase.toLowerCase().includes('argon')) {
+ var argonMode = uci.get('argon', '@global[0]', 'mode');
+ if (argonMode) {
+ if (argonMode.toLowerCase() === 'dark') {
+ return true;
+ } else if (argonMode.toLowerCase() === 'light') {
+ return false;
+ }
+ if (argonMode.toLowerCase() === 'normal' || argonMode.toLowerCase() === 'auto') {
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ return true;
+ }
+ return false;
+ }
+ }
+ }
+
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ return true;
+ }
+
+ return false;
+}
+
+function formatTimestamp(timestamp) {
+ if (!timestamp) return '-';
+ var date = new Date(timestamp);
+ return date.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ fractionalSecondDigits: 3
+ });
+}
+
+function formatResponseCode(code) {
+ var language = getSystemLanguage();
+ if (code === 'Success') return getTranslation('成功', language);
+ if (code === 'Domain not found') return getTranslation('域名未找到', language);
+ if (code === 'Server error') return getTranslation('服务器错误', language);
+ if (code === 'Format error') return getTranslation('格式错误', language);
+ if (code === 'Refused') return getTranslation('拒绝', language);
+ return code || getTranslation('其他', language);
+}
+
+function formatDeviceName(device) {
+ var language = getSystemLanguage();
+ var parts = [];
+ if (device && device.device_name && device.device_name !== '') {
+ parts.push(device.device_name);
+ }
+ // 显示IP地址
+ // 查询时使用source_ip(查询设备的IP)
+ // 响应时使用destination_ip(目标IP,即查询设备的IP),而不是source_ip(DNS服务器的IP)
+ var ip = null;
+ if (device && device.is_query) {
+ // 查询记录:使用source_ip
+ ip = device.source_ip;
+ } else {
+ // 响应记录:使用destination_ip(目标IP)
+ ip = device.destination_ip;
+ }
+ if (ip) {
+ parts.push(ip);
+ }
+ if (parts.length === 0) {
+ return getTranslation('未知设备', language);
+ }
+ return parts.join(' / ');
+}
+
+function formatDnsServer(query) {
+ if (!query) return '-';
+ // 查询时显示目标IP(destination_ip),响应时显示源IP(source_ip)
+ if (query.is_query) {
+ return query.destination_ip || '-';
+ } else {
+ return query.source_ip || '-';
+ }
+}
+
+function formatResponseResult(query) {
+ if (!query) return { display: [], full: [] };
+
+ // 显示响应IP(response_ips),它是一个字符串数组
+ if (query.response_ips && Array.isArray(query.response_ips) && query.response_ips.length > 0) {
+ var maxDisplay = 5; // 最多显示5条
+ var displayRecords = query.response_ips.slice(0, maxDisplay);
+ var fullRecords = query.response_ips;
+
+ return {
+ display: displayRecords,
+ full: fullRecords,
+ hasMore: fullRecords.length > maxDisplay
+ };
+ }
+
+ return { display: [], full: [] };
+}
+
+var callGetDnsQueries = rpc.declare({
+ object: 'luci.bandix',
+ method: 'getDnsQueries',
+ params: ['domain', 'device', 'is_query', 'dns_server', 'page', 'page_size'],
+ expect: {}
+});
+
+var callGetDnsStats = rpc.declare({
+ object: 'luci.bandix',
+ method: 'getDnsStats',
+ expect: {}
+});
+
+return view.extend({
+ load: function () {
+ return Promise.all([
+ uci.load('bandix'),
+ uci.load('luci'),
+ uci.load('argon').catch(function () {
+ return null;
+ })
+ ]);
+ },
+
+ render: function (data) {
+ var language = uci.get('bandix', 'general', 'language');
+ if (!language || language === 'auto') {
+ language = getSystemLanguage();
+ }
+ var darkMode = isDarkMode();
+ var dnsEnabled = uci.get('bandix', 'dns', 'enabled') === '1';
+
+ var style = E('style', {}, `
+ .bandix-dns-container {
+ margin: 0;
+ padding: 16px;
+ background-color: ${darkMode ? '#1a1a1a' : '#f8fafc'};
+ min-height: calc(100vh - 100px);
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ color: ${darkMode ? '#e2e8f0' : '#1f2937'};
+ border-radius: 8px;
+ }
+
+ .bandix-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ }
+
+ .bandix-title {
+ font-size: 1.5rem;
+ font-weight: 600;
+ color: ${darkMode ? '#f1f5f9' : '#1f2937'};
+ margin: 0;
+ }
+
+ .bandix-alert {
+ background-color: ${darkMode ? '#2a2a2a' : '#eff6ff'};
+ border-left: 3px solid ${darkMode ? '#3b82f6' : '#2563eb'};
+ border-radius: 4px;
+ padding: 10px 12px;
+ margin-bottom: 16px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ color: ${darkMode ? '#d0d0d0' : '#1e293b'};
+ font-size: 0.875rem;
+ }
+
+ .bandix-alert-icon {
+ color: ${darkMode ? '#60a5fa' : '#2563eb'};
+ font-size: 0.875rem;
+ font-weight: 700;
+ width: 18px;
+ height: 18px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 2px solid currentColor;
+ border-radius: 50%;
+ flex-shrink: 0;
+ }
+
+ .bandix-card {
+ background-color: ${darkMode ? '#2a2a2a' : 'white'};
+ border-radius: 8px;
+ border: 1px solid ${darkMode ? '#444444' : '#e2e8f0'};
+ box-shadow: 0 2px 8px rgba(0, 0, 0, ${darkMode ? '0.3' : '0.08'});
+ margin-bottom: 24px;
+ overflow: hidden;
+ }
+
+ .bandix-card-header {
+ padding: 16px;
+ border-bottom: 1px solid ${darkMode ? '#444444' : '#e2e8f0'};
+ background-color: ${darkMode ? '#2a2a2a' : '#f8fafc'};
+ }
+
+ .bandix-card-title {
+ font-size: 1.125rem;
+ font-weight: 600;
+ color: ${darkMode ? '#f1f5f9' : '#1f2937'};
+ margin: 0;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .bandix-card-body {
+ padding: 16px;
+ }
+
+ .filter-section {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ margin-bottom: 16px;
+ align-items: center;
+ }
+
+ .filter-group {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .filter-label {
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: ${darkMode ? '#94a3b8' : '#64748b'};
+ white-space: nowrap;
+ }
+
+ .filter-input {
+ padding: 6px 12px;
+ border: 1px solid ${darkMode ? '#444444' : '#cbd5e1'};
+ border-radius: 4px;
+ background-color: ${darkMode ? '#1a1a1a' : 'white'};
+ color: ${darkMode ? '#e2e8f0' : '#1f2937'};
+ font-size: 0.875rem;
+ min-width: 150px;
+ }
+
+ .filter-select {
+ padding: 6px 12px;
+ border: 1px solid ${darkMode ? '#444444' : '#cbd5e1'};
+ border-radius: 4px;
+ background-color: ${darkMode ? '#1a1a1a' : 'white'};
+ color: ${darkMode ? '#e2e8f0' : '#1f2937'};
+ font-size: 0.875rem;
+ cursor: pointer;
+ }
+
+ .btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 12px;
+ border-radius: 4px;
+ font-size: 0.875rem;
+ font-weight: 500;
+ text-decoration: none;
+ border: none;
+ cursor: pointer;
+ transition: all 0.15s ease;
+ }
+
+ .btn-primary {
+ background-color: #3b82f6;
+ color: white;
+ }
+
+ .btn-primary:hover {
+ background-color: #2563eb;
+ }
+
+ .btn-secondary {
+ background-color: ${darkMode ? '#3a3a3a' : '#e5e7eb'};
+ color: ${darkMode ? '#d0d0d0' : '#374151'};
+ }
+
+ .btn-secondary:hover {
+ background-color: ${darkMode ? '#4a4a4a' : '#d1d5db'};
+ }
+
+ .bandix-table {
+ width: 100%;
+ border-collapse: collapse;
+ background-color: transparent;
+ font-size: 0.875rem;
+ }
+
+ .bandix-table th {
+ background-color: ${darkMode ? '#2a2a2a' : '#f8fafc'};
+ padding: 10px 12px;
+ text-align: left;
+ font-weight: 600;
+ color: ${darkMode ? '#d0d0d0' : '#475569'};
+ border-bottom: 2px solid ${darkMode ? '#444444' : '#e2e8f0'};
+ white-space: nowrap;
+ }
+
+ .bandix-table td {
+ padding: 10px 12px;
+ border-bottom: 1px solid ${darkMode ? '#333333' : '#f1f5f9'};
+ color: ${darkMode ? '#d0d0d0' : '#334155'};
+ word-break: break-word;
+ }
+
+ .query-badge {
+ display: inline-block;
+ padding: 2px 8px;
+ border-radius: 4px;
+ font-size: 0.75rem;
+ font-weight: 600;
+ }
+
+ .query-badge.query {
+ background-color: #3b82f6;
+ color: white;
+ }
+
+ .query-badge.response {
+ background-color: #10b981;
+ color: white;
+ }
+
+ .response-code {
+ display: inline-block;
+ padding: 2px 8px;
+ border-radius: 4px;
+ font-size: 0.75rem;
+ font-weight: 600;
+ }
+
+ .response-code.success {
+ background-color: #10b981;
+ color: white;
+ }
+
+ .response-code.error {
+ background-color: #ef4444;
+ color: white;
+ }
+
+ .response-code.warning {
+ background-color: #f59e0b;
+ color: white;
+ }
+
+ .pagination {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-top: 16px;
+ flex-wrap: wrap;
+ gap: 12px;
+ }
+
+ .pagination-info {
+ color: ${darkMode ? '#94a3b8' : '#64748b'};
+ font-size: 0.875rem;
+ }
+
+ .pagination-controls {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .stats-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 16px;
+ margin-bottom: 24px;
+ }
+
+ .stats-card {
+ background-color: ${darkMode ? '#2a2a2a' : 'white'};
+ border-radius: 8px;
+ padding: 16px;
+ border: 1px solid ${darkMode ? '#444444' : '#e2e8f0'};
+ box-shadow: 0 2px 8px rgba(0, 0, 0, ${darkMode ? '0.3' : '0.08'});
+ }
+
+ .stats-card-title {
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: ${darkMode ? '#94a3b8' : '#64748b'};
+ margin: 0 0 8px 0;
+ text-transform: uppercase;
+ letter-spacing: 0.025em;
+ }
+
+ .stats-card-value {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: ${darkMode ? '#f1f5f9' : '#1f2937'};
+ margin: 0;
+ }
+
+ .stats-card-unit {
+ font-size: 0.875rem;
+ color: ${darkMode ? '#94a3b8' : '#64748b'};
+ margin-left: 4px;
+ }
+
+ .stats-card-details {
+ margin-top: 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ }
+
+ .stats-detail-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 0.875rem;
+ }
+
+ .stats-detail-label {
+ color: ${darkMode ? '#9ca3af' : '#6b7280'};
+ font-weight: 500;
+ }
+
+ .stats-detail-value {
+ font-weight: 600;
+ color: ${darkMode ? '#e2e8f0' : '#374151'};
+ }
+
+ .top-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ }
+
+ .top-list-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 0;
+ border-bottom: 1px solid ${darkMode ? '#333333' : '#f1f5f9'};
+ }
+
+ .top-list-item:last-child {
+ border-bottom: none;
+ }
+
+ .top-list-name {
+ flex: 1;
+ color: ${darkMode ? '#e2e8f0' : '#334155'};
+ font-size: 0.875rem;
+ word-break: break-word;
+ }
+
+ .top-list-count {
+ font-weight: 600;
+ color: ${darkMode ? '#f1f5f9' : '#1f2937'};
+ font-size: 0.875rem;
+ margin-left: 12px;
+ }
+
+ .loading-state {
+ text-align: center;
+ padding: 40px;
+ color: ${darkMode ? '#94a3b8' : '#6b7280'};
+ font-style: italic;
+ }
+
+ .error-state {
+ text-align: center;
+ padding: 40px;
+ color: ${darkMode ? '#f87171' : '#ef4444'};
+ }
+
+ .response-ips {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 4px;
+ }
+
+ .response-ip-badge {
+ display: inline-block;
+ padding: 2px 6px;
+ background-color: ${darkMode ? '#3a3a3a' : '#e5e7eb'};
+ border-radius: 4px;
+ font-size: 0.75rem;
+ color: ${darkMode ? '#d0d0d0' : '#374151'};
+ }
+ `);
+ document.head.appendChild(style);
+
+ var container = E('div', { 'class': 'bandix-dns-container' });
+
+ var header = E('div', { 'class': 'bandix-header' }, [
+ E('h1', { 'class': 'bandix-title' }, getTranslation('Bandix DNS 监控', language))
+ ]);
+ container.appendChild(header);
+
+ if (!dnsEnabled) {
+ var alertDiv = E('div', { 'class': 'bandix-alert' }, [
+ E('span', { 'class': 'bandix-alert-icon' }, '!'),
+ E('div', {}, [
+ E('strong', {}, getTranslation('DNS监控未启用', language)),
+ E('p', { 'style': 'margin: 4px 0 0 0;' },
+ getTranslation('请在设置中启用DNS监控功能', language))
+ ])
+ ]);
+ container.appendChild(alertDiv);
+
+ var settingsCard = E('div', { 'class': 'bandix-card' }, [
+ E('div', { 'class': 'bandix-card-body', 'style': 'text-align: center;' }, [
+ E('a', {
+ 'href': '/cgi-bin/luci/admin/network/bandix/settings',
+ 'class': 'btn btn-primary'
+ }, getTranslation('前往设置', language))
+ ])
+ ]);
+ container.appendChild(settingsCard);
+ return container;
+ }
+
+ // DNS 统计信息卡片
+ var statsCard = E('div', { 'class': 'bandix-card' }, [
+ E('div', { 'class': 'bandix-card-body' }, [
+ E('div', { 'id': 'dns-stats-container' }, [
+ E('div', { 'class': 'loading-state' }, getTranslation('正在加载数据...', language))
+ ])
+ ])
+ ]);
+ container.appendChild(statsCard);
+
+ // DNS 查询记录卡片
+ var queriesCard = E('div', { 'class': 'bandix-card' }, [
+ E('div', { 'class': 'bandix-card-header' }, [
+ E('h2', { 'class': 'bandix-card-title' }, getTranslation('DNS 查询记录', language))
+ ]),
+ E('div', { 'class': 'bandix-card-body' }, [
+ E('div', { 'class': 'filter-section' }, [
+ E('div', { 'class': 'filter-group' }, [
+ E('label', { 'class': 'filter-label' }, getTranslation('类型过滤', language) + ':'),
+ E('select', { 'class': 'filter-select', 'id': 'type-filter' }, [
+ E('option', { 'value': '' }, getTranslation('全部', language)),
+ E('option', { 'value': 'true' }, getTranslation('仅查询', language)),
+ E('option', { 'value': 'false' }, getTranslation('仅响应', language))
+ ])
+ ]),
+ E('div', { 'class': 'filter-group' }, [
+ E('label', { 'class': 'filter-label' }, getTranslation('域名过滤', language) + ':'),
+ E('input', {
+ 'type': 'text',
+ 'class': 'filter-input',
+ 'id': 'domain-filter',
+ 'placeholder': getTranslation('搜索域名', language)
+ })
+ ]),
+ E('div', { 'class': 'filter-group' }, [
+ E('label', { 'class': 'filter-label' }, getTranslation('设备过滤', language) + ':'),
+ E('input', {
+ 'type': 'text',
+ 'class': 'filter-input',
+ 'id': 'device-filter',
+ 'placeholder': getTranslation('搜索设备', language)
+ })
+ ]),
+ E('div', { 'class': 'filter-group' }, [
+ E('label', { 'class': 'filter-label' }, getTranslation('DNS服务器过滤', language) + ':'),
+ E('input', {
+ 'type': 'text',
+ 'class': 'filter-input',
+ 'id': 'dns-server-filter',
+ 'placeholder': getTranslation('搜索DNS服务器', language)
+ })
+ ]),
+ E('div', { 'class': 'filter-group', 'style': 'margin-left: auto;' }, [
+ E('button', {
+ 'class': 'btn btn-primary',
+ 'id': 'refresh-queries-btn'
+ }, getTranslation('刷新', language))
+ ])
+ ]),
+ E('div', { 'id': 'dns-queries-container' }, [
+ E('div', { 'class': 'loading-state' }, getTranslation('正在加载数据...', language))
+ ])
+ ])
+ ]);
+ container.appendChild(queriesCard);
+
+ // 状态变量
+ var currentPage = 1;
+ var pageSize = 20;
+ var currentFilters = {
+ domain: '',
+ device: '',
+ is_query: '',
+ dns_server: ''
+ };
+
+ // 更新统计信息
+ var statsInitialized = false;
+ function updateStats() {
+ callGetDnsStats().then(function (result) {
+ var container = document.getElementById('dns-stats-container');
+ if (!container) return;
+ if (!result || result.status !== 'success' || !result.data || !result.data.stats) {
+ if (!statsInitialized) {
+ container.innerHTML = '';
+ container.appendChild(E('div', { 'class': 'error-state' },
+ getTranslation('无法获取数据', language)));
+ }
+ return;
+ }
+
+ var stats = result.data.stats;
+
+ // 如果还没有初始化,创建完整的 UI 结构
+ if (!statsInitialized) {
+ var statsHtml = E('div', {}, [
+ E('div', { 'class': 'stats-grid' }, [
+ E('div', { 'class': 'stats-card' }, [
+ E('div', { 'class': 'stats-card-title' }, getTranslation('总查询数', language)),
+ E('div', { 'class': 'stats-card-value', 'id': 'stat-total-queries' }, stats.total_queries || 0)
+ ]),
+ E('div', { 'class': 'stats-card' }, [
+ E('div', { 'class': 'stats-card-title' }, getTranslation('响应时间', language)),
+ E('div', { 'class': 'stats-card-value', 'id': 'stat-avg-response-time', 'style': 'margin-bottom: 12px;' }, [
+ E('span', {}, (stats.avg_response_time_ms || 0).toFixed(1)),
+ E('span', { 'class': 'stats-card-unit' }, ' ' + getTranslation('毫秒', language))
+ ]),
+ E('div', { 'class': 'stats-card-details', 'id': 'stat-response-time-details' }, [
+ E('div', { 'class': 'stats-detail-row' }, [
+ E('span', { 'class': 'stats-detail-label' }, getTranslation('最快响应时间', language) + ':'),
+ E('span', { 'class': 'stats-detail-value', 'id': 'stat-min-response-time' },
+ (stats.min_response_time_ms || 0) + ' ' + getTranslation('毫秒', language))
+ ]),
+ E('div', { 'class': 'stats-detail-row' }, [
+ E('span', { 'class': 'stats-detail-label' }, getTranslation('最慢响应时间', language) + ':'),
+ E('span', { 'class': 'stats-detail-value', 'id': 'stat-max-response-time' },
+ (stats.max_response_time_ms || 0) + ' ' + getTranslation('毫秒', language))
+ ])
+ ])
+ ]),
+ E('div', { 'class': 'stats-card' }, [
+ E('div', { 'class': 'stats-card-title' }, getTranslation('成功率', language)),
+ E('div', { 'class': 'stats-card-value', 'id': 'stat-success-rate' }, [
+ E('span', {}, ((stats.success_rate || 0) * 100).toFixed(1)),
+ E('span', { 'class': 'stats-card-unit' }, '%')
+ ])
+ ])
+ ]),
+ E('div', { 'style': 'display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-top: 24px;' }, [
+ E('div', { 'class': 'stats-card', 'id': 'top-domains-card' }),
+ E('div', { 'class': 'stats-card', 'id': 'top-query-types-card' }),
+ E('div', { 'class': 'stats-card', 'id': 'top-devices-card' }),
+ E('div', { 'class': 'stats-card', 'id': 'top-dns-servers-card' })
+ ])
+ ]);
+
+ container.innerHTML = '';
+ container.appendChild(statsHtml);
+ statsInitialized = true;
+ }
+
+ // 只更新数字内容
+ var totalQueriesEl = document.getElementById('stat-total-queries');
+ if (totalQueriesEl) {
+ totalQueriesEl.textContent = stats.total_queries || 0;
+ }
+
+ var avgResponseTimeEl = document.getElementById('stat-avg-response-time');
+ if (avgResponseTimeEl && avgResponseTimeEl.firstChild) {
+ avgResponseTimeEl.firstChild.textContent = (stats.avg_response_time_ms || 0).toFixed(1);
+ }
+
+ var minResponseTimeEl = document.getElementById('stat-min-response-time');
+ if (minResponseTimeEl) {
+ minResponseTimeEl.textContent = (stats.min_response_time_ms || 0) + ' ' + getTranslation('毫秒', language);
+ }
+
+ var maxResponseTimeEl = document.getElementById('stat-max-response-time');
+ if (maxResponseTimeEl) {
+ maxResponseTimeEl.textContent = (stats.max_response_time_ms || 0) + ' ' + getTranslation('毫秒', language);
+ }
+
+ var successRateEl = document.getElementById('stat-success-rate');
+ if (successRateEl && successRateEl.firstChild) {
+ successRateEl.firstChild.textContent = ((stats.success_rate || 0) * 100).toFixed(1);
+ }
+
+ // 更新 Top 列表
+ function updateTopList(cardId, titleKey, items, maxItems) {
+ var card = document.getElementById(cardId);
+ if (!card) return;
+
+ if (!items || items.length === 0) {
+ card.style.display = 'none';
+ return;
+ }
+
+ card.style.display = '';
+ var list = card.querySelector('.top-list');
+
+ if (!list) {
+ // 创建列表
+ card.innerHTML = '';
+ card.appendChild(E('div', { 'class': 'stats-card-title' }, getTranslation(titleKey, language)));
+ list = E('ul', { 'class': 'top-list' });
+ card.appendChild(list);
+ }
+
+ var itemsToShow = items.slice(0, maxItems || 10);
+ var listItems = list.querySelectorAll('.top-list-item');
+
+ // 如果列表项数量不匹配,重新创建列表
+ if (listItems.length !== itemsToShow.length) {
+ list.innerHTML = '';
+ itemsToShow.forEach(function (item) {
+ list.appendChild(E('li', { 'class': 'top-list-item' }, [
+ E('span', { 'class': 'top-list-name' }, item.name || '-'),
+ E('span', { 'class': 'top-list-count' }, item.count || 0)
+ ]));
+ });
+ } else {
+ // 只更新文本内容
+ itemsToShow.forEach(function (item, index) {
+ var listItem = listItems[index];
+ if (listItem) {
+ var nameEl = listItem.querySelector('.top-list-name');
+ var countEl = listItem.querySelector('.top-list-count');
+ if (nameEl) nameEl.textContent = item.name || '-';
+ if (countEl) countEl.textContent = item.count || 0;
+ }
+ });
+ }
+ }
+
+ updateTopList('top-domains-card', '最常查询域名', stats.top_domains, 10);
+ updateTopList('top-query-types-card', '最常用查询类型', stats.top_query_types);
+ updateTopList('top-devices-card', '最活跃设备', stats.top_devices, 10);
+ updateTopList('top-dns-servers-card', '最常用DNS服务器', stats.top_dns_servers, 5);
+ }).catch(function (error) {
+ console.error('Failed to load DNS stats:', error);
+ var container = document.getElementById('dns-stats-container');
+ if (!container) return;
+ if (!statsInitialized) {
+ container.innerHTML = '';
+ container.appendChild(E('div', { 'class': 'error-state' },
+ getTranslation('无法获取数据', language)));
+ }
+ });
+ }
+
+ // 更新查询记录
+ function updateQueries() {
+ var container = document.getElementById('dns-queries-container');
+ if (!container) return;
+
+ // 检查是否有现有内容
+ var hasContent = container.querySelector('.bandix-table') || container.querySelector('.loading-state') || container.querySelector('.error-state');
+
+ // 保存当前容器高度,避免跳动(只在有内容时)
+ var currentHeight = container.offsetHeight;
+ if (currentHeight > 0 && hasContent) {
+ container.style.minHeight = currentHeight + 'px';
+ }
+
+ // 显示加载状态,但保持容器结构(只在有内容时显示遮罩层)
+ var loadingDiv = container.querySelector('.loading-overlay');
+ if (hasContent) {
+ if (!loadingDiv) {
+ var overlayBg = darkMode ? 'rgba(42, 42, 42, 0.9)' : 'rgba(255, 255, 255, 0.9)';
+ loadingDiv = E('div', {
+ 'class': 'loading-overlay',
+ 'style': 'position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: ' + overlayBg + '; display: flex; align-items: center; justify-content: center; z-index: 10; color: ' + (darkMode ? '#e2e8f0' : '#1f2937') + ';'
+ }, getTranslation('正在加载数据...', language));
+ container.style.position = 'relative';
+ container.appendChild(loadingDiv);
+ } else {
+ loadingDiv.style.display = 'flex';
+ }
+ } else {
+ // 如果没有内容,使用简单的加载状态
+ container.innerHTML = '';
+ container.appendChild(E('div', { 'class': 'loading-state' },
+ getTranslation('正在加载数据...', language)));
+ }
+
+ callGetDnsQueries(
+ currentFilters.domain,
+ currentFilters.device,
+ currentFilters.is_query,
+ currentFilters.dns_server,
+ currentPage,
+ pageSize
+ ).then(function (result) {
+ // 隐藏或移除加载状态
+ if (loadingDiv) {
+ loadingDiv.remove();
+ }
+
+ // 恢复最小高度和定位
+ container.style.minHeight = '';
+ if (!hasContent) {
+ container.style.position = '';
+ }
+
+ if (!result || result.status !== 'success' || !result.data) {
+ container.innerHTML = '';
+ container.appendChild(E('div', { 'class': 'error-state' },
+ getTranslation('无法获取数据', language)));
+ return;
+ }
+
+ var queries = result.data.queries || [];
+ var total = result.data.total || 0;
+ var totalPages = result.data.total_pages || 1;
+
+ if (queries.length === 0) {
+ container.innerHTML = '';
+ container.appendChild(E('div', { 'class': 'loading-state' },
+ getTranslation('无数据', language)));
+ return;
+ }
+
+ // 移除旧的表格和分页
+ var oldTable = container.querySelector('.bandix-table');
+ var oldPagination = container.querySelector('.pagination');
+ var oldLoadingState = container.querySelector('.loading-state');
+ if (oldTable) oldTable.remove();
+ if (oldPagination) oldPagination.remove();
+ if (oldLoadingState) oldLoadingState.remove();
+
+ // 确保容器是相对定位(用于遮罩层)
+ container.style.position = 'relative';
+
+ var table = E('table', { 'class': 'bandix-table' }, [
+ E('thead', {}, [
+ E('tr', {}, [
+ E('th', { 'style': 'width: 180px;' }, getTranslation('时间', language)),
+ E('th', { 'style': 'width: 200px;' }, getTranslation('域名', language)),
+ E('th', { 'style': 'width: 100px;' }, getTranslation('查询类型', language)),
+ E('th', { 'style': 'width: 100px;' }, getTranslation('类型', language)),
+ E('th', { 'style': 'width: 100px;' }, getTranslation('响应时间', language)),
+ E('th', { 'style': 'width: 200px;' }, getTranslation('设备', language)),
+ E('th', { 'style': 'width: 140px;' }, getTranslation('DNS服务器', language)),
+ E('th', { 'style': 'width: 200px;' }, getTranslation('响应结果', language))
+ ])
+ ]),
+ E('tbody', {}, queries.map(function (query) {
+ return E('tr', {}, [
+ E('td', {}, formatTimestamp(query.timestamp)),
+ E('td', {}, query.domain || '-'),
+ E('td', {}, query.query_type || '-'),
+ E('td', {}, [
+ E('span', {
+ 'class': 'query-badge ' + (query.is_query ? 'query' : 'response')
+ }, query.is_query ? getTranslation('查询', language) : getTranslation('响应', language))
+ ]),
+ E('td', {}, query.response_time_ms ? query.response_time_ms + ' ' + getTranslation('毫秒', language) : '-'),
+ E('td', {}, formatDeviceName(query)),
+ E('td', {}, formatDnsServer(query)),
+ E('td', {}, [
+ E('div', {
+ 'class': 'response-ips',
+ 'title': (function() {
+ var result = formatResponseResult(query);
+ if (result.full.length === 0) {
+ return '';
+ }
+ return result.full.join('\n');
+ })()
+ }, (function() {
+ var result = formatResponseResult(query);
+ if (result.display.length === 0) {
+ return [E('span', { 'class': 'response-ip-badge' }, '-')];
+ }
+ var badges = result.display.map(function (item) {
+ return E('span', { 'class': 'response-ip-badge' }, item);
+ });
+ if (result.hasMore) {
+ badges.push(E('span', { 'class': 'response-ip-badge', 'style': 'opacity: 0.7;' }, '...'));
+ }
+ return badges;
+ })())
+ ])
+ ]);
+ }))
+ ]);
+
+ var pagination = E('div', { 'class': 'pagination' }, [
+ E('div', { 'class': 'pagination-info' },
+ getTranslation('第', language) + ' ' + currentPage + ' ' + getTranslation('页,共', language) + ' ' + totalPages + ',' + getTranslation('共', language) + ' ' + total + ' ' + getTranslation('条记录', language)
+ ),
+ E('div', { 'class': 'pagination-controls' }, [
+ E('select', {
+ 'class': 'filter-select',
+ 'id': 'page-size-select',
+ 'style': 'margin-right: 8px;'
+ }, [
+ E('option', { 'value': '10', 'selected': pageSize === 10 }, '10'),
+ E('option', { 'value': '20', 'selected': pageSize === 20 }, '20'),
+ E('option', { 'value': '50', 'selected': pageSize === 50 }, '50'),
+ E('option', { 'value': '100', 'selected': pageSize === 100 }, '100')
+ ]),
+ E('button', {
+ 'class': 'btn btn-secondary',
+ 'id': 'prev-page-btn',
+ 'disabled': currentPage <= 1 ? 'disabled' : null
+ }, getTranslation('上一页', language)),
+ E('button', {
+ 'class': 'btn btn-secondary',
+ 'id': 'next-page-btn',
+ 'disabled': currentPage >= totalPages ? 'disabled' : null
+ }, getTranslation('下一页', language))
+ ])
+ ]);
+
+ container.appendChild(table);
+ container.appendChild(pagination);
+
+ // 绑定分页事件
+ var prevBtn = document.getElementById('prev-page-btn');
+ var nextBtn = document.getElementById('next-page-btn');
+ var pageSizeSelect = document.getElementById('page-size-select');
+
+ // 设置按钮的 disabled 状态
+ if (prevBtn) {
+ if (currentPage <= 1) {
+ prevBtn.setAttribute('disabled', 'disabled');
+ } else {
+ prevBtn.removeAttribute('disabled');
+ }
+ prevBtn.onclick = function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ if (currentPage > 1) {
+ currentPage--;
+ updateQueries();
+ }
+ };
+ }
+
+ if (nextBtn) {
+ if (currentPage >= totalPages) {
+ nextBtn.setAttribute('disabled', 'disabled');
+ } else {
+ nextBtn.removeAttribute('disabled');
+ }
+ nextBtn.onclick = function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ if (currentPage < totalPages) {
+ currentPage++;
+ updateQueries();
+ }
+ };
+ }
+
+ if (pageSizeSelect) {
+ pageSizeSelect.value = pageSize.toString();
+ pageSizeSelect.onchange = function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ pageSize = parseInt(this.value);
+ currentPage = 1;
+ updateQueries();
+ };
+ }
+ }).catch(function (error) {
+ console.error('Failed to load DNS queries:', error);
+ var container = document.getElementById('dns-queries-container');
+ if (!container) return;
+ container.innerHTML = '';
+ container.appendChild(E('div', { 'class': 'error-state' },
+ getTranslation('无法获取数据', language)));
+ });
+ }
+
+ // 初始化数据加载 - 延迟执行确保 DOM 元素已添加
+ setTimeout(function () {
+ updateStats();
+ updateQueries();
+
+ // 实时搜索功能(带防抖)
+ var domainFilter = document.getElementById('domain-filter');
+ var deviceFilter = document.getElementById('device-filter');
+ var dnsServerFilter = document.getElementById('dns-server-filter');
+ var typeFilter = document.getElementById('type-filter');
+ var refreshBtn = document.getElementById('refresh-queries-btn');
+
+ if (domainFilter && deviceFilter && dnsServerFilter && typeFilter) {
+ var searchTimer = null;
+
+ function performSearch() {
+ currentFilters.domain = domainFilter.value.trim();
+ currentFilters.device = deviceFilter.value.trim();
+ currentFilters.dns_server = dnsServerFilter.value.trim();
+ currentFilters.is_query = typeFilter.value;
+ currentPage = 1;
+ updateQueries();
+ }
+
+ // 防抖函数
+ function debounceSearch() {
+ if (searchTimer) {
+ clearTimeout(searchTimer);
+ }
+ searchTimer = setTimeout(performSearch, 300);
+ }
+
+ // 输入框实时搜索(带防抖)
+ domainFilter.addEventListener('input', debounceSearch);
+ deviceFilter.addEventListener('input', debounceSearch);
+ dnsServerFilter.addEventListener('input', debounceSearch);
+
+ // 下拉框立即搜索(不需要防抖)
+ typeFilter.addEventListener('change', performSearch);
+
+ // 刷新按钮
+ if (refreshBtn) {
+ refreshBtn.addEventListener('click', function () {
+ updateQueries();
+ });
+ }
+ }
+ }, 100);
+
+ // 轮询更新统计信息(每1秒),查询记录不自动刷新
+ poll.add(updateStats, 1);
+
+ return container;
+ }
+});
+
diff --git a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/settings.js b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/settings.js
index 9a728dc..7e931f5 100644
--- a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/settings.js
+++ b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/settings.js
@@ -10,12 +10,15 @@ const translations = {
'基本设置': '基本设置',
'流量监控设置': '流量监控设置',
'连接监控设置': '连接监控设置',
+ 'DNS监控设置': 'DNS监控设置',
'Bandix 基本配置': 'Bandix 基本配置',
'配置 Bandix 服务的基本参数': '配置 Bandix 服务的基本参数',
'Bandix 流量监控配置': 'Bandix 流量监控配置',
'配置流量监控相关参数': '配置流量监控相关参数',
'Bandix 连接监控配置': 'Bandix 连接监控配置',
'配置连接监控相关参数': '配置连接监控相关参数',
+ 'Bandix DNS监控配置': 'Bandix DNS监控配置',
+ '配置DNS监控相关参数': '配置DNS监控相关参数',
'启用': '启用',
'启用 Bandix 流量监控服务': '启用 Bandix 流量监控服务',
'启用流量监控': '启用流量监控',
@@ -56,6 +59,9 @@ const translations = {
'数据目录': '数据目录',
'Bandix 数据存储目录': 'Bandix 数据存储目录',
'启用 Bandix 连接监控功能': '启用 Bandix 连接监控功能',
+ '启用 Bandix DNS监控功能': '启用 Bandix DNS监控功能',
+ 'DNS最大记录数': 'DNS最大记录数',
+ '设置DNS查询记录的最大保存数量': '设置DNS查询记录的最大保存数量,超过此数量将删除最旧的记录',
'持久化历史数据': '持久化历史数据',
'启用数据持久化功能': '启用数据持久化功能,只有启用此选项后才会持久化到磁盘'
},
@@ -63,12 +69,15 @@ const translations = {
'基本设置': '基本設置',
'流量监控设置': '流量監控設置',
'连接监控设置': '連接監控設置',
+ 'DNS监控设置': 'DNS監控設置',
'Bandix 基本配置': 'Bandix 基本配置',
'配置 Bandix 服务的基本参数': '配置 Bandix 服務的基本參數',
'Bandix 流量监控配置': 'Bandix 流量監控配置',
'配置流量监控相关参数': '配置流量監控相關參數',
'Bandix 连接监控配置': 'Bandix 連接監控配置',
'配置连接监控相关参数': '配置連接監控相關參數',
+ 'Bandix DNS监控配置': 'Bandix DNS監控配置',
+ '配置DNS监控相关参数': '配置DNS監控相關參數',
'启用': '啟用',
'启用 Bandix 流量监控服务': '啟用 Bandix 流量監控服務',
'启用流量监控': '啟用流量監控',
@@ -109,6 +118,9 @@ const translations = {
'数据目录': '數據目錄',
'Bandix 数据存储目录': 'Bandix 數據存儲目錄',
'启用 Bandix 连接监控功能': '啟用 Bandix 連接監控功能',
+ '启用 Bandix DNS监控功能': '啟用 Bandix DNS監控功能',
+ 'DNS最大记录数': 'DNS最大記錄數',
+ '设置DNS查询记录的最大保存数量': '設定DNS查詢記錄的最大保存數量,超過此數量將刪除最舊的記錄',
'持久化历史数据': '持久化歷史數據',
'启用数据持久化功能': '啟用數據持久化功能,只有啟用此選項後才會持久化到磁碟'
},
@@ -116,16 +128,20 @@ const translations = {
'基本设置': 'Basic Settings',
'流量监控设置': 'Traffic Monitor Settings',
'连接监控设置': 'Connection Monitor Settings',
+ 'DNS监控设置': 'DNS Monitor Settings',
'Bandix 基本配置': 'Bandix Basic Configuration',
'配置 Bandix 服务的基本参数': 'Configure basic parameters for Bandix service',
'Bandix 流量监控配置': 'Bandix Traffic Monitor Configuration',
'配置流量监控相关参数': 'Configure traffic monitoring related parameters',
'Bandix 连接监控配置': 'Bandix Connection Monitor Configuration',
'配置连接监控相关参数': 'Configure connection monitoring related parameters',
+ 'Bandix DNS监控配置': 'Bandix DNS Monitor Configuration',
+ '配置DNS监控相关参数': 'Configure DNS monitoring related parameters',
'启用': 'Enable',
'启用 Bandix 流量监控服务': 'Enable Bandix Traffic Monitor Service',
'启用流量监控': 'Enable Traffic Monitoring',
'启用连接监控': 'Enable Connection Monitoring',
+ '启用DNS监控': 'Enable DNS Monitoring',
'界面语言': 'Interface Language',
'选择 Bandix 流量监控的显示语言': 'Select the display language for Bandix Traffic Monitor',
'简体中文': 'Simplified Chinese',
@@ -162,6 +178,9 @@ const translations = {
'数据目录': 'Data Directory',
'Bandix 数据存储目录': 'Bandix data storage directory',
'启用 Bandix 连接监控功能': 'Enable Bandix connection monitoring',
+ '启用 Bandix DNS监控功能': 'Enable Bandix DNS monitoring',
+ 'DNS最大记录数': 'DNS Max Records',
+ '设置DNS查询记录的最大保存数量': 'Set the maximum number of DNS query records to keep. Older records will be deleted when this limit is exceeded',
'持久化历史数据': 'Persist History Data',
'启用数据持久化功能': 'Enable data persistence functionality, data will only be persisted to disk when this option is enabled'
},
@@ -169,16 +188,20 @@ const translations = {
'基本设置': 'Paramètres de Base',
'流量监控设置': 'Paramètres de Surveillance du Trafic',
'连接监控设置': 'Paramètres de Surveillance des Connexions',
+ 'DNS监控设置': 'Paramètres de Surveillance DNS',
'Bandix 基本配置': 'Configuration de Base Bandix',
'配置 Bandix 服务的基本参数': 'Configurer les paramètres de base du service Bandix',
'Bandix 流量监控配置': 'Configuration de Surveillance du Trafic Bandix',
'配置流量监控相关参数': 'Configurer les paramètres liés à la surveillance du trafic',
'Bandix 连接监控配置': 'Configuration de Surveillance des Connexions Bandix',
'配置连接监控相关参数': 'Configurer les paramètres liés à la surveillance des connexions',
+ 'Bandix DNS监控配置': 'Configuration de Surveillance DNS Bandix',
+ '配置DNS监控相关参数': 'Configurer les paramètres liés à la surveillance DNS',
'启用': 'Activer',
'启用 Bandix 流量监控服务': 'Activer le Service de Surveillance du Trafic Bandix',
'启用流量监控': 'Activer la Surveillance du Trafic',
'启用连接监控': 'Activer la Surveillance des Connexions',
+ '启用DNS监控': 'Activer la Surveillance DNS',
'界面语言': 'Langue de l\'Interface',
'选择 Bandix 流量监控的显示语言': 'Sélectionner la langue d\'affichage pour le Moniteur de Trafic Bandix',
'简体中文': 'Chinois Simplifié',
@@ -215,6 +238,9 @@ const translations = {
'数据目录': 'Répertoire de Données',
'Bandix 数据存储目录': 'Répertoire de stockage de données Bandix',
'启用 Bandix 连接监控功能': 'Activer la surveillance des connexions Bandix',
+ '启用 Bandix DNS监控功能': 'Activer la surveillance DNS Bandix',
+ 'DNS最大记录数': 'Nombre Maximum d\'Enregistrements DNS',
+ '设置DNS查询记录的最大保存数量': 'Définir le nombre maximum d\'enregistrements de requêtes DNS à conserver. Les enregistrements plus anciens seront supprimés lorsque cette limite est dépassée',
'持久化历史数据': 'Persister les Données Historiques',
'启用数据持久化功能': 'Activer la fonctionnalité de persistance des données, les données ne seront persistées sur le disque que lorsque cette option est activée'
},
@@ -222,16 +248,20 @@ const translations = {
'基本设置': '基本設定',
'流量监控设置': 'トラフィック監視設定',
'连接监控设置': '接続監視設定',
+ 'DNS监控设置': 'DNS監視設定',
'Bandix 基本配置': 'Bandix 基本設定',
'配置 Bandix 服务的基本参数': 'Bandix サービスの基本パラメータを設定',
'Bandix 流量监控配置': 'Bandix トラフィック監視設定',
'配置流量监控相关参数': 'トラフィック監視関連パラメータを設定',
'Bandix 连接监控配置': 'Bandix 接続監視設定',
'配置连接监控相关参数': '接続監視関連パラメータを設定',
+ 'Bandix DNS监控配置': 'Bandix DNS監視設定',
+ '配置DNS监控相关参数': 'DNS監視関連パラメータを設定',
'启用': '有効',
'启用 Bandix 流量监控服务': 'Bandix トラフィックモニターサービスを有効にする',
'启用流量监控': 'トラフィック監視を有効にする',
'启用连接监控': '接続監視を有効にする',
+ '启用DNS监控': 'DNS監視を有効にする',
'界面语言': 'インターフェース言語',
'选择 Bandix 流量监控的显示语言': 'Bandix トラフィックモニターの表示言語を選択',
'简体中文': '簡体字中国語',
@@ -268,6 +298,9 @@ const translations = {
'数据目录': 'データディレクトリ',
'Bandix 数据存储目录': 'Bandix データ保存ディレクトリ',
'启用 Bandix 连接监控功能': 'Bandix 接続監視機能を有効にする',
+ '启用 Bandix DNS监控功能': 'Bandix DNS監視機能を有効にする',
+ 'DNS最大记录数': 'DNS最大記録数',
+ '设置DNS查询记录的最大保存数量': 'DNSクエリ記録の最大保存数を設定。この数を超えると、最も古い記録が削除されます',
'持久化历史数据': '履歴データの永続化',
'启用数据持久化功能': 'データ永続化機能を有効にする。このオプションが有効な場合のみ、データがディスクに永続化されます'
},
@@ -275,16 +308,20 @@ const translations = {
'基本设置': 'Основные Настройки',
'流量监控设置': 'Настройки Мониторинга Трафика',
'连接监控设置': 'Настройки Мониторинга Соединений',
+ 'DNS监控设置': 'Настройки Мониторинга DNS',
'Bandix 基本配置': 'Базовая Конфигурация Bandix',
'配置 Bandix 服务的基本参数': 'Настроить основные параметры службы Bandix',
'Bandix 流量监控配置': 'Конфигурация Мониторинга Трафика Bandix',
'配置流量监控相关参数': 'Настроить параметры, связанные с мониторингом трафика',
'Bandix 连接监控配置': 'Конфигурация Мониторинга Соединений Bandix',
'配置连接监控相关参数': 'Настроить параметры, связанные с мониторингом соединений',
+ 'Bandix DNS监控配置': 'Конфигурация Мониторинга DNS Bandix',
+ '配置DNS监控相关参数': 'Настроить параметры, связанные с мониторингом DNS',
'启用': 'Включить',
'启用 Bandix 流量监控服务': 'Включить Службу Мониторинга Трафика Bandix',
'启用流量监控': 'Включить Мониторинг Трафика',
'启用连接监控': 'Включить Мониторинг Соединений',
+ '启用DNS监控': 'Включить Мониторинг DNS',
'界面语言': 'Язык Интерфейса',
'选择 Bandix 流量监控的显示语言': 'Выберите язык отображения для Монитора Трафика Bandix',
'简体中文': 'Упрощенный Китайский',
@@ -321,6 +358,9 @@ const translations = {
'数据目录': 'Каталог Данных',
'Bandix 数据存储目录': 'Каталог хранения данных Bandix',
'启用 Bandix 连接监控功能': 'Включить мониторинг соединений Bandix',
+ '启用 Bandix DNS监控功能': 'Включить мониторинг DNS Bandix',
+ 'DNS最大记录数': 'Максимальное Количество Записей DNS',
+ '设置DNS查询记录的最大保存数量': 'Установить максимальное количество записей DNS-запросов для хранения. Более старые записи будут удалены при превышении этого лимита',
'持久化历史数据': 'Персистентность Исторических Данных',
'启用数据持久化功能': 'Включить функциональность персистентности данных, данные будут сохраняться на диск только при включении этой опции'
}
@@ -408,6 +448,9 @@ return view.extend({
if (!uci.get('bandix', 'connections')) {
uci.add('bandix', 'connections', 'connections');
}
+ if (!uci.get('bandix', 'dns')) {
+ uci.add('bandix', 'dns', 'dns');
+ }
var language = uci.get('bandix', 'general', 'language');
if (!language || language === 'auto') {
@@ -676,6 +719,24 @@ return view.extend({
o.default = '0';
o.rmempty = false;
+ // 4. DNS监控设置部分 (dns)
+ s = m.section(form.NamedSection, 'dns', 'dns', getTranslation('DNS监控设置', language));
+ s.description = getTranslation('配置DNS监控相关参数', language);
+ s.addremove = false;
+
+ o = s.option(form.Flag, 'enabled', getTranslation('启用DNS监控', language),
+ getTranslation('启用 Bandix DNS监控功能', language));
+ o.default = '0';
+ o.rmempty = false;
+
+ // 添加DNS最大记录数选项
+ o = s.option(form.Value, 'dns_max_records', getTranslation('DNS最大记录数', language),
+ getTranslation('设置DNS查询记录的最大保存数量', language));
+ o.datatype = 'uinteger';
+ o.placeholder = '10000';
+ o.default = '10000';
+ o.rmempty = false;
+
return m.render();
}
});
\ No newline at end of file
diff --git a/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix b/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix
index 25b2c0e..c4a8aef 100755
--- a/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix
+++ b/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix
@@ -10,6 +10,8 @@ readonly BANDIX_DEVICES_API="$BANDIX_API_BASE/api/traffic/devices"
readonly BANDIX_LIMITS_API="$BANDIX_API_BASE/api/traffic/limits"
readonly BANDIX_METRICS_API="$BANDIX_API_BASE/api/traffic/metrics"
readonly BANDIX_CONNECTION_API="$BANDIX_API_BASE/api/connection/devices"
+readonly BANDIX_DNS_QUERIES_API="$BANDIX_API_BASE/api/dns/queries"
+readonly BANDIX_DNS_STATS_API="$BANDIX_API_BASE/api/dns/stats"
# 通用函数:创建简单的JSON响应
make_value() {
@@ -223,6 +225,72 @@ get_connection_devices() {
echo "$response"
}
+# 获取 DNS 查询记录
+get_dns_queries() {
+ # 检查 DNS 监控是否启用
+ local dns_enabled=$(uci get bandix.dns.enabled 2>/dev/null)
+ if [ "$dns_enabled" != "1" ]; then
+ make_error "DNS monitoring is not enabled"
+ return
+ fi
+
+ # 构建查询参数
+ local query_params=""
+ local domain="$1"
+ local device="$2"
+ local is_query="$3"
+ local dns_server="$4"
+ local page="$5"
+ local page_size="$6"
+
+ [ -n "$domain" ] && query_params="${query_params}domain=$(printf '%s' "$domain" | sed 's/ /%20/g')&"
+ [ -n "$device" ] && query_params="${query_params}device=$(printf '%s' "$device" | sed 's/ /%20/g')&"
+ [ -n "$is_query" ] && query_params="${query_params}is_query=$is_query&"
+ [ -n "$dns_server" ] && query_params="${query_params}dns_server=$(printf '%s' "$dns_server" | sed 's/ /%20/g')&"
+ [ -n "$page" ] && query_params="${query_params}page=$page&"
+ [ -n "$page_size" ] && query_params="${query_params}page_size=$page_size&"
+
+ # 移除末尾的 &
+ query_params=$(echo "$query_params" | sed 's/&$//')
+
+ local url="$BANDIX_DNS_QUERIES_API"
+ [ -n "$query_params" ] && url="${url}?${query_params}"
+
+ # 从 Bandix API 获取 DNS 查询数据
+ local response=$(curl -s --connect-timeout 2 --max-time 10 -X GET "$url" 2>/dev/null)
+
+ # 检查API调用是否成功
+ if [ $? -ne 0 ] || [ -z "$response" ]; then
+ make_error "Failed to connect to Bandix service"
+ return
+ fi
+
+ # 直接返回API结果
+ echo "$response"
+}
+
+# 获取 DNS 统计信息
+get_dns_stats() {
+ # 检查 DNS 监控是否启用
+ local dns_enabled=$(uci get bandix.dns.enabled 2>/dev/null)
+ if [ "$dns_enabled" != "1" ]; then
+ make_error "DNS monitoring is not enabled"
+ return
+ fi
+
+ # 从 Bandix API 获取 DNS 统计数据
+ local response=$(curl -s --connect-timeout 2 --max-time 10 -X GET "$BANDIX_DNS_STATS_API" 2>/dev/null)
+
+ # 检查API调用是否成功
+ if [ $? -ne 0 ] || [ -z "$response" ]; then
+ make_error "Failed to connect to Bandix service"
+ return
+ fi
+
+ # 直接返回API结果
+ echo "$response"
+}
+
case "$1" in
list)
json_init
@@ -247,6 +315,18 @@ case "$1" in
json_add_object "getConnection"
json_close_object
+ json_add_object "getDnsQueries"
+ json_add_string "domain"
+ json_add_string "device"
+ json_add_string "is_query"
+ json_add_string "dns_server"
+ json_add_int "page"
+ json_add_int "page_size"
+ json_close_object
+
+ json_add_object "getDnsStats"
+ json_close_object
+
json_dump
json_cleanup
;;
@@ -351,6 +431,40 @@ case "$1" in
# logger "luci.bandix: getConnection called"
get_connection_devices
;;
+ getDnsQueries)
+ # logger "luci.bandix: getDnsQueries called"
+ # 从 stdin 读取 JSON 参数
+ read input
+
+ if [ -n "$input" ]; then
+ # 解析参数
+ domain=$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)
+ [ -z "$domain" ] && domain=$(echo "$input" | jsonfilter -e '$.domain' 2>/dev/null)
+
+ device=$(echo "$input" | jsonfilter -e '$[1]' 2>/dev/null)
+ [ -z "$device" ] && device=$(echo "$input" | jsonfilter -e '$.device' 2>/dev/null)
+
+ is_query=$(echo "$input" | jsonfilter -e '$[2]' 2>/dev/null)
+ [ -z "$is_query" ] && is_query=$(echo "$input" | jsonfilter -e '$.is_query' 2>/dev/null)
+
+ dns_server=$(echo "$input" | jsonfilter -e '$[3]' 2>/dev/null)
+ [ -z "$dns_server" ] && dns_server=$(echo "$input" | jsonfilter -e '$.dns_server' 2>/dev/null)
+
+ page=$(echo "$input" | jsonfilter -e '$[4]' 2>/dev/null)
+ [ -z "$page" ] && page=$(echo "$input" | jsonfilter -e '$.page' 2>/dev/null)
+
+ page_size=$(echo "$input" | jsonfilter -e '$[5]' 2>/dev/null)
+ [ -z "$page_size" ] && page_size=$(echo "$input" | jsonfilter -e '$.page_size' 2>/dev/null)
+
+ get_dns_queries "$domain" "$device" "$is_query" "$dns_server" "$page" "$page_size"
+ else
+ get_dns_queries "" "" "" "" "" ""
+ fi
+ ;;
+ getDnsStats)
+ # logger "luci.bandix: getDnsStats called"
+ get_dns_stats
+ ;;
esac
;;
esac
diff --git a/luci-app-bandix/root/usr/share/luci/menu.d/luci-app-bandix.json b/luci-app-bandix/root/usr/share/luci/menu.d/luci-app-bandix.json
index 917aa01..d57191f 100644
--- a/luci-app-bandix/root/usr/share/luci/menu.d/luci-app-bandix.json
+++ b/luci-app-bandix/root/usr/share/luci/menu.d/luci-app-bandix.json
@@ -27,9 +27,17 @@
"path": "bandix/connection"
}
},
+ "admin/network/bandix/dns": {
+ "title": "DNS",
+ "order": 20,
+ "action": {
+ "type": "view",
+ "path": "bandix/dns"
+ }
+ },
"admin/network/bandix/settings": {
"title": "Settings",
- "order": 20,
+ "order": 25,
"action": {
"type": "view",
"path": "bandix/settings"
diff --git a/luci-app-bandix/root/usr/share/rpcd/acl.d/luci-app-bandix.json b/luci-app-bandix/root/usr/share/rpcd/acl.d/luci-app-bandix.json
index 0a37922..4821a00 100644
--- a/luci-app-bandix/root/usr/share/rpcd/acl.d/luci-app-bandix.json
+++ b/luci-app-bandix/root/usr/share/rpcd/acl.d/luci-app-bandix.json
@@ -8,7 +8,9 @@
"getMetrics",
"setRateLimit",
"getConnection",
- "setHostname"
+ "setHostname",
+ "getDnsQueries",
+ "getDnsStats"
]
},
"uci": [
@@ -22,7 +24,9 @@
"getStatus",
"getMetrics",
"getConnection",
- "setHostname"
+ "setHostname",
+ "getDnsQueries",
+ "getDnsStats"
]
},
"uci": [
diff --git a/luci-app-nikki/Makefile b/luci-app-nikki/Makefile
index d225057..6b6ca3b 100644
--- a/luci-app-nikki/Makefile
+++ b/luci-app-nikki/Makefile
@@ -1,6 +1,6 @@
include $(TOPDIR)/rules.mk
-PKG_VERSION:=1.24.3
+PKG_VERSION:=1.24.4
LUCI_TITLE:=LuCI Support for nikki
LUCI_DEPENDS:=+luci-base +nikki
diff --git a/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js b/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js
index 36ee5cf..6c1f34e 100644
--- a/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js
+++ b/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js
@@ -249,6 +249,10 @@ return view.extend({
o.datatype = 'cidr4';
o.placeholder = _('Unmodified');
+ o = s.taboption('dns', form.Value, 'fake_ip6_range', _('Fake-IP6 Range'));
+ o.datatype = 'cidr6';
+ o.placeholder = _('Unmodified');
+
o = s.taboption('dns', form.Flag, 'fake_ip_filter', _('Overwrite Fake-IP Filter'));
o.rmempty = false;
diff --git a/luci-app-nikki/po/templates/nikki.pot b/luci-app-nikki/po/templates/nikki.pot
index 778067c..c52617b 100644
--- a/luci-app-nikki/po/templates/nikki.pot
+++ b/luci-app-nikki/po/templates/nikki.pot
@@ -31,7 +31,7 @@ msgstr ""
msgid "Allow Lan"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:263
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:267
msgid "Allow Mode"
msgstr ""
@@ -48,19 +48,19 @@ msgstr ""
msgid "App Version"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:486
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:490
msgid "Append Rule"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:417
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:421
msgid "Append Rule Provider"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:473
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:477
msgid "Behavior"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:262
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:266
msgid "Block Mode"
msgstr ""
@@ -143,15 +143,15 @@ msgstr ""
msgid "Debug Log"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:509
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:513
msgid "Destination IP"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:513
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:517
msgid "Destination IP Geo"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:510
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:514
msgid "Destination Port"
msgstr ""
@@ -181,15 +181,15 @@ msgstr ""
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:208
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:229
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:239
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:268
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:274
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:280
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:286
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:292
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:361
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:367
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:373
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:560
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:272
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:278
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:284
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:290
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:296
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:365
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:371
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:377
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:565
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:38
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:45
msgid "Disable"
@@ -211,32 +211,32 @@ msgstr ""
msgid "Disable TCP Keep Alive"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:277
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:281
msgid "DoH Prefer HTTP/3"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:309
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:504
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:313
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:508
msgid "Domain Name"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:512
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:516
msgid "Domain Name Geo"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:507
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:511
msgid "Domain Name Keyword"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:508
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:512
msgid "Domain Name Regex"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:505
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:509
msgid "Domain Name Suffix"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:506
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:510
msgid "Domain Name Wildcard"
msgstr ""
@@ -248,27 +248,27 @@ msgstr ""
msgid "Edit DNS Hijacks"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:255
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:259
msgid "Edit Fake-IP Filters"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:298
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:302
msgid "Edit Hosts"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:340
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:344
msgid "Edit Nameserver Policies"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:317
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:321
msgid "Edit Nameservers"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:420
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:424
msgid "Edit Rule Providers"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:489
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:493
msgid "Edit Rules"
msgstr ""
@@ -295,23 +295,23 @@ msgstr ""
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:226
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:230
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:240
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:269
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:275
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:281
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:287
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:293
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:306
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:325
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:348
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:358
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:273
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:279
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:285
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:291
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:297
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:310
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:329
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:352
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:362
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:368
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:374
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:400
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:428
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:497
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:561
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:569
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:366
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:372
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:378
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:404
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:432
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:501
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:566
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:574
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:33
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:66
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:77
@@ -332,11 +332,11 @@ msgstr ""
msgid "External Control Config"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:265
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:269
msgid "Fake-IP Cache"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:259
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:263
msgid "Fake-IP Filter Mode"
msgstr ""
@@ -348,19 +348,23 @@ msgstr ""
msgid "Fake-IP Range"
msgstr ""
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:252
+msgid "Fake-IP6 Range"
+msgstr ""
+
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/app.js:132
msgid "Fast Reload"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:467
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:471
msgid "File Format"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:461
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:465
msgid "File Path"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:455
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:459
msgid "File Size Limit"
msgstr ""
@@ -373,7 +377,7 @@ msgstr ""
msgid "File:"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:379
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:383
msgid "Force Sniff Domain Name"
msgstr ""
@@ -394,39 +398,39 @@ msgstr ""
msgid "Generate & Download"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:539
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:544
msgid "GeoData Loader"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:533
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:538
msgid "GeoIP Format"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:554
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:559
msgid "GeoIP(ASN) Url"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:551
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:556
msgid "GeoIP(DAT) Url"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:548
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:553
msgid "GeoIP(MMDB) Url"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:545
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:550
msgid "GeoSite Url"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:557
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:562
msgid "GeoX Auto Update"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:531
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:536
msgid "GeoX Config"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:563
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:568
msgid "GeoX Update Interval"
msgstr ""
@@ -478,7 +482,7 @@ msgstr ""
msgid "IPv6 Proxy"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:386
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:390
msgid "Ignore Sniff Domain Name"
msgstr ""
@@ -515,12 +519,12 @@ msgstr ""
msgid "Match Process"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:351
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:515
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:355
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:519
msgid "Matcher"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:543
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:548
msgid "Memory Conservative Loader"
msgstr ""
@@ -532,7 +536,7 @@ msgstr ""
msgid "Mixin Config"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:567
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:572
msgid "Mixin File Content"
msgstr ""
@@ -544,12 +548,12 @@ msgstr ""
msgid "Mode"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:434
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:438
msgid "Name"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:335
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:354
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:339
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:358
msgid "Nameserver"
msgstr ""
@@ -558,12 +562,12 @@ msgstr ""
msgid "Nikki"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:526
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:530
msgid "No Resolve"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:448
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:519
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:452
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:523
msgid "Node"
msgstr ""
@@ -595,35 +599,35 @@ msgstr ""
msgid "Overwrite DNS Hijack"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:412
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:416
msgid "Overwrite Destination"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:252
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:256
msgid "Overwrite Fake-IP Filter"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:376
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:380
msgid "Overwrite Force Sniff Domain Name"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:295
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:299
msgid "Overwrite Hosts"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:383
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:387
msgid "Overwrite Ignore Sniff Domain Name"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:314
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:318
msgid "Overwrite Nameserver"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:337
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:341
msgid "Overwrite Nameserver Policy"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:390
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:394
msgid "Overwrite Sniff By Protocol"
msgstr ""
@@ -631,11 +635,11 @@ msgstr ""
msgid "Password"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:569
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:574
msgid "Please go to the editor tab to edit the file for mixin"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:409
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:413
msgid "Port"
msgstr ""
@@ -643,7 +647,7 @@ msgstr ""
msgid "Prefer"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:511
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:515
msgid "Process Name"
msgstr ""
@@ -656,7 +660,7 @@ msgstr ""
msgid "Profile for Startup"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:403
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:407
msgid "Protocol"
msgstr ""
@@ -699,7 +703,7 @@ msgstr ""
msgid "Remote"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:271
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:275
msgid "Respect Rules"
msgstr ""
@@ -711,7 +715,7 @@ msgstr ""
msgid "Router Proxy"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:415
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:419
msgid "Rule Config"
msgstr ""
@@ -723,7 +727,7 @@ msgstr ""
msgid "Rule Provider:"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:503
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:507
msgid "Rule Set"
msgstr ""
@@ -756,19 +760,19 @@ msgstr ""
msgid "Skip System IPv6 Check"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:393
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:397
msgid "Sniff By Protocol"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:370
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:374
msgid "Sniff Pure IP"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:364
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:368
msgid "Sniff Redir-Host"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:356
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:360
msgid "Sniffer Config"
msgstr ""
@@ -784,7 +788,7 @@ msgstr ""
msgid "Stack Size Soft Limit"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:542
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:547
msgid "Standard Loader"
msgstr ""
@@ -867,9 +871,9 @@ msgstr ""
msgid "Transparent Proxy with Mihomo on OpenWrt."
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:328
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:437
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:501
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:332
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:441
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:505
msgid "Type"
msgstr ""
@@ -938,23 +942,24 @@ msgstr ""
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:238
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:244
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:250
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:261
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:267
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:273
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:279
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:285
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:291
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:360
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:366
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:372
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:535
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:541
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:254
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:265
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:271
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:277
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:283
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:295
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:364
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:370
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:376
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:540
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:546
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:549
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:552
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:555
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:559
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:565
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:551
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:554
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:557
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:560
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:564
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:570
msgid "Unmodified"
msgstr ""
@@ -970,7 +975,7 @@ msgstr ""
msgid "Update Dashboard"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:480
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:484
msgid "Update Interval"
msgstr ""
@@ -978,15 +983,15 @@ msgstr ""
msgid "Upload Profile"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:443
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:447
msgid "Url"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:293
msgid "Use Hosts"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:283
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:287
msgid "Use System Hosts"
msgstr ""
diff --git a/luci-app-nikki/po/zh_Hans/nikki.po b/luci-app-nikki/po/zh_Hans/nikki.po
index c47b926..ecbd21a 100644
--- a/luci-app-nikki/po/zh_Hans/nikki.po
+++ b/luci-app-nikki/po/zh_Hans/nikki.po
@@ -38,7 +38,7 @@ msgstr "全部端口"
msgid "Allow Lan"
msgstr "允许局域网访问"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:263
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:267
msgid "Allow Mode"
msgstr "白名单模式"
@@ -55,19 +55,19 @@ msgstr "插件日志"
msgid "App Version"
msgstr "插件版本"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:486
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:490
msgid "Append Rule"
msgstr "追加规则"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:417
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:421
msgid "Append Rule Provider"
msgstr "追加规则提供者"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:473
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:477
msgid "Behavior"
msgstr "行为"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:262
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:266
msgid "Block Mode"
msgstr "黑名单模式"
@@ -150,15 +150,15 @@ msgstr "DNS 模式"
msgid "Debug Log"
msgstr "调试日志"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:509
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:513
msgid "Destination IP"
msgstr "目标 IP"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:513
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:517
msgid "Destination IP Geo"
msgstr "目标 IP(Geo)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:510
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:514
msgid "Destination Port"
msgstr "目标端口"
@@ -188,15 +188,15 @@ msgstr "直连模式"
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:208
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:229
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:239
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:268
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:274
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:280
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:286
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:292
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:361
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:367
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:373
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:560
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:272
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:278
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:284
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:290
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:296
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:365
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:371
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:377
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:565
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:38
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:45
msgid "Disable"
@@ -218,32 +218,32 @@ msgstr "禁用回环检测"
msgid "Disable TCP Keep Alive"
msgstr "禁用 TCP Keep Alive"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:277
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:281
msgid "DoH Prefer HTTP/3"
msgstr "DoH 优先 HTTP/3"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:309
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:504
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:313
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:508
msgid "Domain Name"
msgstr "域名"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:512
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:516
msgid "Domain Name Geo"
msgstr "域名(Geo)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:507
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:511
msgid "Domain Name Keyword"
msgstr "域名(关键字)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:508
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:512
msgid "Domain Name Regex"
msgstr "域名(正则表达式)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:505
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:509
msgid "Domain Name Suffix"
msgstr "域名(后缀)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:506
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:510
msgid "Domain Name Wildcard"
msgstr "域名(通配符)"
@@ -255,27 +255,27 @@ msgstr "编辑身份验证"
msgid "Edit DNS Hijacks"
msgstr "编辑 DNS 劫持"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:255
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:259
msgid "Edit Fake-IP Filters"
msgstr "编辑 Fake-IP 过滤列表"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:298
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:302
msgid "Edit Hosts"
msgstr "编辑 Hosts"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:340
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:344
msgid "Edit Nameserver Policies"
msgstr "编辑 DNS 服务器查询策略"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:317
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:321
msgid "Edit Nameservers"
msgstr "编辑 DNS 服务器"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:420
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:424
msgid "Edit Rule Providers"
msgstr "编辑规则提供者"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:489
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:493
msgid "Edit Rules"
msgstr "编辑规则"
@@ -302,23 +302,23 @@ msgstr "编辑器"
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:226
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:230
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:240
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:269
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:275
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:281
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:287
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:293
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:306
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:325
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:348
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:358
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:273
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:279
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:285
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:291
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:297
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:310
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:329
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:352
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:362
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:368
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:374
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:400
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:428
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:497
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:561
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:569
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:366
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:372
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:378
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:404
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:432
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:501
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:566
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:574
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:33
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:66
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:77
@@ -339,11 +339,11 @@ msgstr "到期时间"
msgid "External Control Config"
msgstr "外部控制配置"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:265
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:269
msgid "Fake-IP Cache"
msgstr "Fake-IP 缓存"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:259
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:263
msgid "Fake-IP Filter Mode"
msgstr "Fake-IP 过滤模式"
@@ -355,19 +355,23 @@ msgstr "Fake-IP Ping 劫持"
msgid "Fake-IP Range"
msgstr "Fake-IP 范围"
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:252
+msgid "Fake-IP6 Range"
+msgstr "Fake-IP6 范围"
+
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/app.js:132
msgid "Fast Reload"
msgstr "快速重载"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:467
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:471
msgid "File Format"
msgstr "文件格式"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:461
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:465
msgid "File Path"
msgstr "文件路径"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:455
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:459
msgid "File Size Limit"
msgstr "文件大小限制"
@@ -380,7 +384,7 @@ msgstr "用于混入的文件"
msgid "File:"
msgstr "文件:"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:379
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:383
msgid "Force Sniff Domain Name"
msgstr "强制嗅探的域名"
@@ -401,39 +405,39 @@ msgstr "全局配置"
msgid "Generate & Download"
msgstr "生成并下载"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:539
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:544
msgid "GeoData Loader"
msgstr "GeoData 加载器"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:533
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:538
msgid "GeoIP Format"
msgstr "GeoIP 格式"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:554
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:559
msgid "GeoIP(ASN) Url"
msgstr "GeoIP(ASN) 下载地址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:551
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:556
msgid "GeoIP(DAT) Url"
msgstr "GeoIP(DAT) 下载地址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:548
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:553
msgid "GeoIP(MMDB) Url"
msgstr "GeoIP(MMDB) 下载地址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:545
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:550
msgid "GeoSite Url"
msgstr "GeoSite 下载地址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:557
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:562
msgid "GeoX Auto Update"
msgstr "定时更新GeoX文件"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:531
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:536
msgid "GeoX Config"
msgstr "GeoX 配置"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:563
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:568
msgid "GeoX Update Interval"
msgstr "GeoX 文件更新间隔"
@@ -485,7 +489,7 @@ msgstr "IPv6 DNS 劫持"
msgid "IPv6 Proxy"
msgstr "IPv6 代理"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:386
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:390
msgid "Ignore Sniff Domain Name"
msgstr "忽略嗅探的域名"
@@ -522,12 +526,12 @@ msgstr "最大传输单元"
msgid "Match Process"
msgstr "匹配进程"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:351
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:515
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:355
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:519
msgid "Matcher"
msgstr "匹配"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:543
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:548
msgid "Memory Conservative Loader"
msgstr "为内存受限设备优化的加载器"
@@ -539,7 +543,7 @@ msgstr "混合端口"
msgid "Mixin Config"
msgstr "混入配置"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:567
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:572
msgid "Mixin File Content"
msgstr "混入文件内容"
@@ -551,12 +555,12 @@ msgstr "混入选项"
msgid "Mode"
msgstr "模式"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:434
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:438
msgid "Name"
msgstr "名称"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:335
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:354
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:339
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:358
msgid "Nameserver"
msgstr "DNS 服务器"
@@ -565,12 +569,12 @@ msgstr "DNS 服务器"
msgid "Nikki"
msgstr "Nikki"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:526
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:530
msgid "No Resolve"
msgstr "不解析"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:448
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:519
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:452
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:523
msgid "Node"
msgstr "节点"
@@ -602,35 +606,35 @@ msgstr "覆盖身份验证"
msgid "Overwrite DNS Hijack"
msgstr "覆盖 DNS 劫持"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:412
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:416
msgid "Overwrite Destination"
msgstr "将嗅探结果作为连接目标"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:252
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:256
msgid "Overwrite Fake-IP Filter"
msgstr "覆盖 Fake-IP 过滤列表"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:376
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:380
msgid "Overwrite Force Sniff Domain Name"
msgstr "覆盖强制嗅探的域名"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:295
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:299
msgid "Overwrite Hosts"
msgstr "覆盖 Hosts"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:383
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:387
msgid "Overwrite Ignore Sniff Domain Name"
msgstr "覆盖忽略嗅探的域名"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:314
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:318
msgid "Overwrite Nameserver"
msgstr "覆盖 DNS 服务器"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:337
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:341
msgid "Overwrite Nameserver Policy"
msgstr "覆盖 DNS 服务器查询策略"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:390
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:394
msgid "Overwrite Sniff By Protocol"
msgstr "覆盖按协议嗅探"
@@ -638,11 +642,11 @@ msgstr "覆盖按协议嗅探"
msgid "Password"
msgstr "密码"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:569
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:574
msgid "Please go to the editor tab to edit the file for mixin"
msgstr "请前往编辑器标签编辑用于混入的文件"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:409
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:413
msgid "Port"
msgstr "端口"
@@ -650,7 +654,7 @@ msgstr "端口"
msgid "Prefer"
msgstr "优先"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:511
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:515
msgid "Process Name"
msgstr "进程名"
@@ -663,7 +667,7 @@ msgstr "配置文件"
msgid "Profile for Startup"
msgstr "用于启动的配置文件"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:403
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:407
msgid "Protocol"
msgstr "协议"
@@ -706,7 +710,7 @@ msgstr "重载服务"
msgid "Remote"
msgstr "远程"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:271
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:275
msgid "Respect Rules"
msgstr "遵循分流规则"
@@ -718,7 +722,7 @@ msgstr "重启服务"
msgid "Router Proxy"
msgstr "路由器代理"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:415
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:419
msgid "Rule Config"
msgstr "规则配置"
@@ -730,7 +734,7 @@ msgstr "规则模式"
msgid "Rule Provider:"
msgstr "规则提供者:"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:503
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:507
msgid "Rule Set"
msgstr "规则集"
@@ -763,19 +767,19 @@ msgstr "滚动到底部"
msgid "Skip System IPv6 Check"
msgstr "跳过系统 IPv6 检查"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:393
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:397
msgid "Sniff By Protocol"
msgstr "按协议嗅探"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:370
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:374
msgid "Sniff Pure IP"
msgstr "嗅探纯 IP 连接"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:364
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:368
msgid "Sniff Redir-Host"
msgstr "嗅探 Redir-Host 流量"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:356
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:360
msgid "Sniffer Config"
msgstr "嗅探器配置"
@@ -791,7 +795,7 @@ msgstr "栈大小硬限制"
msgid "Stack Size Soft Limit"
msgstr "栈大小软限制"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:542
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:547
msgid "Standard Loader"
msgstr "标准加载器"
@@ -874,9 +878,9 @@ msgstr "总量"
msgid "Transparent Proxy with Mihomo on OpenWrt."
msgstr "在 OpenWrt 上使用 Mihomo 进行透明代理。"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:328
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:437
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:501
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:332
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:441
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:505
msgid "Type"
msgstr "类型"
@@ -945,23 +949,24 @@ msgstr "无限制"
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:238
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:244
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:250
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:261
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:267
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:273
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:279
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:285
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:291
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:360
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:366
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:372
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:535
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:541
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:254
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:265
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:271
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:277
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:283
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:295
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:364
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:370
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:376
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:540
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:546
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:549
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:552
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:555
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:559
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:565
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:551
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:554
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:557
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:560
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:564
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:570
msgid "Unmodified"
msgstr "不修改"
@@ -977,7 +982,7 @@ msgstr "更新时间"
msgid "Update Dashboard"
msgstr "更新面板"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:480
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:484
msgid "Update Interval"
msgstr "更新间隔"
@@ -985,15 +990,15 @@ msgstr "更新间隔"
msgid "Upload Profile"
msgstr "上传配置文件"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:443
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:447
msgid "Url"
msgstr "下载地址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:293
msgid "Use Hosts"
msgstr "使用 Hosts"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:283
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:287
msgid "Use System Hosts"
msgstr "使用系统的 Hosts"
diff --git a/luci-app-nikki/po/zh_Hant/nikki.po b/luci-app-nikki/po/zh_Hant/nikki.po
index fdf7252..cf53ece 100644
--- a/luci-app-nikki/po/zh_Hant/nikki.po
+++ b/luci-app-nikki/po/zh_Hant/nikki.po
@@ -38,7 +38,7 @@ msgstr "所有埠"
msgid "Allow Lan"
msgstr "允許區域網路存取"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:263
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:267
msgid "Allow Mode"
msgstr "白名單模式"
@@ -55,19 +55,19 @@ msgstr "應用程式日誌"
msgid "App Version"
msgstr "應用程式版本"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:486
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:490
msgid "Append Rule"
msgstr "追加規則"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:417
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:421
msgid "Append Rule Provider"
msgstr "追加規則提供者"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:473
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:477
msgid "Behavior"
msgstr "行為"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:262
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:266
msgid "Block Mode"
msgstr "黑名單模式"
@@ -150,15 +150,15 @@ msgstr "DNS 模式"
msgid "Debug Log"
msgstr "除錯日誌"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:509
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:513
msgid "Destination IP"
msgstr "目標 IP"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:513
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:517
msgid "Destination IP Geo"
msgstr "目標 IP(地理位置)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:510
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:514
msgid "Destination Port"
msgstr "目標埠"
@@ -188,15 +188,15 @@ msgstr "直連模式"
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:208
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:229
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:239
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:268
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:274
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:280
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:286
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:292
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:361
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:367
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:373
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:560
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:272
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:278
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:284
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:290
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:296
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:365
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:371
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:377
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:565
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:38
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:45
msgid "Disable"
@@ -218,32 +218,32 @@ msgstr "停用迴路檢測"
msgid "Disable TCP Keep Alive"
msgstr "停用 TCP Keep Alive"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:277
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:281
msgid "DoH Prefer HTTP/3"
msgstr "DoH 優先使用 HTTP/3"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:309
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:504
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:313
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:508
msgid "Domain Name"
msgstr "網域名稱"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:512
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:516
msgid "Domain Name Geo"
msgstr "網域名稱(地理位置)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:507
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:511
msgid "Domain Name Keyword"
msgstr "網域名稱(關鍵字)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:508
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:512
msgid "Domain Name Regex"
msgstr "網域名稱(正則表達式)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:505
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:509
msgid "Domain Name Suffix"
msgstr "網域名稱(後綴)"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:506
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:510
msgid "Domain Name Wildcard"
msgstr "網域名稱(通配符)"
@@ -255,27 +255,27 @@ msgstr "編輯身分驗證"
msgid "Edit DNS Hijacks"
msgstr "編輯 DNS 劫持"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:255
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:259
msgid "Edit Fake-IP Filters"
msgstr "編輯 Fake-IP 過濾清單"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:298
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:302
msgid "Edit Hosts"
msgstr "編輯 Hosts"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:340
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:344
msgid "Edit Nameserver Policies"
msgstr "編輯 DNS 伺服器查詢策略"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:317
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:321
msgid "Edit Nameservers"
msgstr "編輯 DNS 伺服器"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:420
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:424
msgid "Edit Rule Providers"
msgstr "編輯規則提供者"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:489
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:493
msgid "Edit Rules"
msgstr "編輯規則"
@@ -302,23 +302,23 @@ msgstr "編輯器"
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:226
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:230
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:240
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:269
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:275
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:281
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:287
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:293
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:306
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:325
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:348
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:358
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:273
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:279
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:285
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:291
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:297
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:310
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:329
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:352
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:362
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:368
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:374
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:400
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:428
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:497
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:561
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:569
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:366
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:372
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:378
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:404
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:432
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:501
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:566
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:574
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:33
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:66
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js:77
@@ -339,11 +339,11 @@ msgstr "到期時間"
msgid "External Control Config"
msgstr "外部控制設定"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:265
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:269
msgid "Fake-IP Cache"
msgstr "Fake-IP 快取"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:259
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:263
msgid "Fake-IP Filter Mode"
msgstr "Fake-IP 過濾模式"
@@ -355,19 +355,23 @@ msgstr "Fake-IP Ping 劫持"
msgid "Fake-IP Range"
msgstr "Fake-IP 範圍"
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:252
+msgid "Fake-IP6 Range"
+msgstr "Fake-IP6 範圍"
+
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/app.js:132
msgid "Fast Reload"
msgstr "快速重載"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:467
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:471
msgid "File Format"
msgstr "檔案格式"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:461
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:465
msgid "File Path"
msgstr "檔案路徑"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:455
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:459
msgid "File Size Limit"
msgstr "檔案大小限制"
@@ -380,7 +384,7 @@ msgstr "用於混入的檔案"
msgid "File:"
msgstr "檔案:"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:379
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:383
msgid "Force Sniff Domain Name"
msgstr "強制嗅探的網域名稱"
@@ -401,39 +405,39 @@ msgstr "一般設定"
msgid "Generate & Download"
msgstr "生成並下載"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:539
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:544
msgid "GeoData Loader"
msgstr "GeoData 載入器"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:533
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:538
msgid "GeoIP Format"
msgstr "GeoIP 格式"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:554
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:559
msgid "GeoIP(ASN) Url"
msgstr "GeoIP(ASN) 下載網址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:551
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:556
msgid "GeoIP(DAT) Url"
msgstr "GeoIP(DAT) 下載網址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:548
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:553
msgid "GeoIP(MMDB) Url"
msgstr "GeoIP(MMDB) 下載網址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:545
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:550
msgid "GeoSite Url"
msgstr "GeoSite 下載網址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:557
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:562
msgid "GeoX Auto Update"
msgstr "定時更新 GeoX 檔案"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:531
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:536
msgid "GeoX Config"
msgstr "GeoX 設定"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:563
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:568
msgid "GeoX Update Interval"
msgstr "GeoX 檔案更新間隔"
@@ -485,7 +489,7 @@ msgstr "IPv6 DNS 劫持"
msgid "IPv6 Proxy"
msgstr "IPv6 代理"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:386
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:390
msgid "Ignore Sniff Domain Name"
msgstr "忽略嗅探的網域名稱"
@@ -522,12 +526,12 @@ msgstr "最大傳輸單元"
msgid "Match Process"
msgstr "匹配程序"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:351
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:515
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:355
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:519
msgid "Matcher"
msgstr "匹配器"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:543
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:548
msgid "Memory Conservative Loader"
msgstr "為記憶體受限裝置最佳化的載入器"
@@ -539,7 +543,7 @@ msgstr "混合埠"
msgid "Mixin Config"
msgstr "混入設定"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:567
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:572
msgid "Mixin File Content"
msgstr "混入檔案內容"
@@ -551,12 +555,12 @@ msgstr "混入選項"
msgid "Mode"
msgstr "模式"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:434
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:438
msgid "Name"
msgstr "名稱"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:335
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:354
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:339
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:358
msgid "Nameserver"
msgstr "DNS 伺服器"
@@ -565,12 +569,12 @@ msgstr "DNS 伺服器"
msgid "Nikki"
msgstr "Nikki"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:526
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:530
msgid "No Resolve"
msgstr "不解析"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:448
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:519
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:452
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:523
msgid "Node"
msgstr "節點"
@@ -602,35 +606,35 @@ msgstr "覆寫身分驗證"
msgid "Overwrite DNS Hijack"
msgstr "覆寫 DNS 劫持"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:412
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:416
msgid "Overwrite Destination"
msgstr "將嗅探結果作為連線目標"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:252
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:256
msgid "Overwrite Fake-IP Filter"
msgstr "覆寫 Fake-IP 過濾清單"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:376
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:380
msgid "Overwrite Force Sniff Domain Name"
msgstr "覆寫強制嗅探的網域名稱"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:295
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:299
msgid "Overwrite Hosts"
msgstr "覆寫 Hosts"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:383
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:387
msgid "Overwrite Ignore Sniff Domain Name"
msgstr "覆寫忽略嗅探的網域名稱"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:314
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:318
msgid "Overwrite Nameserver"
msgstr "覆寫 DNS 伺服器"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:337
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:341
msgid "Overwrite Nameserver Policy"
msgstr "覆寫 DNS 伺服器查詢策略"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:390
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:394
msgid "Overwrite Sniff By Protocol"
msgstr "覆寫按協定嗅探"
@@ -638,11 +642,11 @@ msgstr "覆寫按協定嗅探"
msgid "Password"
msgstr "密碼"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:569
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:574
msgid "Please go to the editor tab to edit the file for mixin"
msgstr "請前往編輯器標籤編輯用於混入的檔案"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:409
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:413
msgid "Port"
msgstr "埠"
@@ -650,7 +654,7 @@ msgstr "埠"
msgid "Prefer"
msgstr "優先"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:511
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:515
msgid "Process Name"
msgstr "程序名稱"
@@ -663,7 +667,7 @@ msgstr "設定檔"
msgid "Profile for Startup"
msgstr "用於啟動的設定檔"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:403
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:407
msgid "Protocol"
msgstr "協定"
@@ -706,7 +710,7 @@ msgstr "重新載入服務"
msgid "Remote"
msgstr "遠端"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:271
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:275
msgid "Respect Rules"
msgstr "遵循分流規則"
@@ -718,7 +722,7 @@ msgstr "重新啟動服務"
msgid "Router Proxy"
msgstr "路由器代理"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:415
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:419
msgid "Rule Config"
msgstr "規則設定"
@@ -730,7 +734,7 @@ msgstr "規則模式"
msgid "Rule Provider:"
msgstr "規則提供者:"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:503
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:507
msgid "Rule Set"
msgstr "規則集"
@@ -763,19 +767,19 @@ msgstr "捲動到底部"
msgid "Skip System IPv6 Check"
msgstr "跳過系統 IPv6 檢查"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:393
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:397
msgid "Sniff By Protocol"
msgstr "按協定嗅探"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:370
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:374
msgid "Sniff Pure IP"
msgstr "嗅探純 IP 連線"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:364
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:368
msgid "Sniff Redir-Host"
msgstr "嗅探 Redir-Host 流量"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:356
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:360
msgid "Sniffer Config"
msgstr "嗅探器設定"
@@ -791,7 +795,7 @@ msgstr ""
msgid "Stack Size Soft Limit"
msgstr ""
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:542
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:547
msgid "Standard Loader"
msgstr "標準載入器"
@@ -874,9 +878,9 @@ msgstr "總計"
msgid "Transparent Proxy with Mihomo on OpenWrt."
msgstr "在 OpenWrt 上使用 Mihomo 進行透明代理."
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:328
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:437
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:501
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:332
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:441
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:505
msgid "Type"
msgstr "類型"
@@ -945,23 +949,24 @@ msgstr "無限制"
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:238
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:244
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:250
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:261
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:267
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:273
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:279
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:285
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:291
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:360
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:366
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:372
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:535
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:541
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:254
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:265
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:271
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:277
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:283
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:295
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:364
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:370
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:376
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:540
#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:546
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:549
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:552
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:555
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:559
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:565
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:551
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:554
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:557
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:560
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:564
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:570
msgid "Unmodified"
msgstr "不修改"
@@ -977,7 +982,7 @@ msgstr "更新時間"
msgid "Update Dashboard"
msgstr "更新儀表板"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:480
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:484
msgid "Update Interval"
msgstr "更新間隔"
@@ -985,15 +990,15 @@ msgstr "更新間隔"
msgid "Upload Profile"
msgstr "上傳設定檔"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:443
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:447
msgid "Url"
msgstr "下載網址"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:289
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:293
msgid "Use Hosts"
msgstr "使用 Hosts"
-#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:283
+#: applications/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js:287
msgid "Use System Hosts"
msgstr "使用系統的 Hosts"
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
index c255149..0a27fb6 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
@@ -20,6 +20,7 @@ local port_validate = function(self, value, t)
end
local nodes_table = {}
+local shunt_list = {}
for k, e in ipairs(api.get_valid_nodes()) do
nodes_table[#nodes_table + 1] = e
end
@@ -200,6 +201,9 @@ o:depends({ _tcp_node_bool = "1" })
for k, v in pairs(nodes_table) do
s.fields["tcp_node"]:value(v.id, v["remark"])
s.fields["udp_node"]:value(v.id, v["remark"])
+ if v.protocol and v.protocol == "_shunt" then
+ shunt_list[#shunt_list + 1] = v
+ end
end
o = s:option(DummyValue, "_udp_node_bool", "")
@@ -311,11 +315,7 @@ o.default = "0"
o:depends({ _tcp_node_bool = "1" })
---- DNS Forward Mode
-o = s:option(ListValue, "dns_mode", translate("Filter Mode"),
- "" .. translate(
- "If the node uses Xray/Sing-Box shunt, select the matching filter mode (Xray/Sing-Box).") ..
- "")
-o:depends({ _tcp_node_bool = "1" })
+o = s:option(ListValue, "dns_mode", translate("Filter Mode"))
if api.is_finded("dns2socks") then
o:value("dns2socks", "dns2socks")
end
@@ -325,6 +325,19 @@ end
if has_xray then
o:value("xray", "Xray")
end
+o.remove = function(self, section)
+ local f = s.fields["tcp_node"]
+ local id_val = f and f:formvalue(section) or ""
+ if id_val == "" then
+ return m:del(section, self.option)
+ end
+ for k, v in pairs(shunt_list) do
+ if v.id == id_val then
+ local new_val = (v.type == "Xray") and "xray" or "sing-box"
+ return m:set(section, self.option, new_val)
+ end
+ end
+end
o = s:option(ListValue, "xray_dns_mode", translate("Request protocol"))
o:value("tcp", "TCP")
@@ -437,4 +450,21 @@ o:value("direct", translate("Direct DNS"))
o.description = desc .. ""
o:depends({dns_shunt = "dnsmasq", tcp_proxy_mode = "proxy", chn_list = "direct"})
+for k, v in pairs(nodes_table) do
+ if v.protocol and v.protocol ~= "_shunt" then
+ s.fields["dns_mode"]:depends({ _tcp_node_bool = "1", tcp_node = v.id })
+ end
+end
+for k, v in pairs(shunt_list) do
+ if v.type == "Xray" and has_xray then
+ s.fields["xray_dns_mode"]:depends({ _tcp_node_bool = "1", tcp_node = v.id })
+ end
+ if v.type == "sing-box" and has_singbox then
+ s.fields["singbox_dns_mode"]:depends({ _tcp_node_bool = "1", tcp_node = v.id })
+ end
+ if has_xray or has_singbox then
+ s.fields["remote_dns_client_ip"]:depends({ tcp_node = v.id })
+ end
+end
+
return m
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
index 63d6063..1f1f468 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
@@ -321,11 +321,37 @@ o:depends("direct_dns_mode", "tcp")
o = s:taboption("DNS", Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
o.default = "0"
+-- TCP分流时dns过滤模式保存逻辑
+function dns_mode_save(section)
+ for k, v in pairs(shunt_list) do
+ local f = s.fields[v.id .. "-type"]
+ if f then
+ local type_val = f:formvalue(section)
+ if type_val and (type_val == "Xray" or type_val == "sing-box") then
+ local dns_shunt_val = s.fields["dns_shunt"]:formvalue(section)
+ local dns_mode_val = (dns_shunt_val ~= "smartdns") and "dns_mode" or "smartdns_dns_mode"
+ local current_val = m:get(section, dns_mode_val) or ""
+ local new_val = (type_val == "Xray") and "xray" or "sing-box"
+
+ if current_val ~= new_val then
+ m:set(section, dns_mode_val, new_val)
+ m:del(section, (dns_mode_val == "dns_mode") and "smartdns_dns_mode" or "dns_mode")
+ end
+
+ local dns_field = s.fields[type_val == "Xray" and "xray_dns_mode" or "singbox_dns_mode"]
+ local v2ray_dns_mode = dns_field and dns_field:formvalue(section)
+ if v2ray_dns_mode and m:get(section, "v2ray_dns_mode") ~= v2ray_dns_mode then
+ m:set(section, "v2ray_dns_mode", v2ray_dns_mode)
+ end
+
+ break
+ end
+ end
+ end
+end
+
---- DNS Forward Mode
-o = s:taboption("DNS", ListValue, "dns_mode", translate("Filter Mode"),
- "" .. translate(
- "If the node uses Xray/Sing-Box shunt, select the matching filter mode (Xray/Sing-Box).") ..
- "")
+o = s:taboption("DNS", ListValue, "dns_mode", translate("Filter Mode"))
o:value("udp", translatef("Requery DNS By %s", "UDP"))
o:value("tcp", translatef("Requery DNS By %s", "TCP"))
if api.is_finded("dns2socks") then
@@ -337,16 +363,19 @@ end
if has_xray then
o:value("xray", "Xray")
end
-if api.is_finded("smartdns") then
- o:depends({ dns_shunt = "smartdns", ['!reverse'] = true })
+o:depends({ dns_shunt = "chinadns-ng", tcp_node = "" })
+o:depends({ dns_shunt = "dnsmasq", tcp_node = "" })
+o.remove = function(self, section)
+ local f = s.fields["smartdns_dns_mode"]
+ if f and f:formvalue(section) then
+ return m:del(section, self.option)
+ end
+ dns_mode_save(section)
end
---- SmartDNS Forward Mode
if api.is_finded("smartdns") then
- o = s:taboption("DNS", ListValue, "smartdns_dns_mode", translate("Filter Mode"),
- "" .. translate(
- "If the node uses Xray/Sing-Box shunt, select the matching filter mode (Xray/Sing-Box).") ..
- "")
+ o = s:taboption("DNS", ListValue, "smartdns_dns_mode", translate("Filter Mode"))
o:value("socks", "Socks")
if has_singbox then
o:value("sing-box", "Sing-Box")
@@ -354,7 +383,14 @@ if api.is_finded("smartdns") then
if has_xray then
o:value("xray", "Xray")
end
- o:depends({ dns_shunt = "smartdns" })
+ o:depends({ dns_shunt = "smartdns", tcp_node = "" })
+ o.remove = function(self, section)
+ local f = s.fields["dns_mode"]
+ if f and f:formvalue(section) then
+ return m:del(section, self.option)
+ end
+ dns_mode_save(section)
+ end
o = s:taboption("DNS", DynamicList, "smartdns_remote_dns", translate("Remote DNS"))
o:value("tcp://1.1.1.1")
@@ -399,7 +435,7 @@ if api.is_finded("smartdns") then
end
end
-o = s:taboption("DNS", ListValue, "xray_dns_mode", translate("Request protocol"))
+o = s:taboption("DNS", ListValue, "xray_dns_mode", translate("Remote DNS") .. " " .. translate("Request protocol"))
o:value("tcp", "TCP")
o:value("tcp+doh", "TCP + DoH (" .. translate("A/AAAA type") .. ")")
o:depends("dns_mode", "xray")
@@ -413,7 +449,7 @@ o.write = function(self, section, value)
end
end
-o = s:taboption("DNS", ListValue, "singbox_dns_mode", translate("Request protocol"))
+o = s:taboption("DNS", ListValue, "singbox_dns_mode", translate("Remote DNS") .. " " .. translate("Request protocol"))
o:value("tcp", "TCP")
o:value("doh", "DoH")
o:depends("dns_mode", "sing-box")
@@ -738,6 +774,21 @@ for k, v in pairs(nodes_table) do
else
s2.fields["node"]:value(v.id, v["remark"])
end
+
+ if v.protocol and v.protocol ~= "_shunt" then
+ s.fields["dns_mode"]:depends({ dns_shunt = "chinadns-ng", tcp_node = v.id })
+ s.fields["dns_mode"]:depends({ dns_shunt = "dnsmasq", tcp_node = v.id })
+ if api.is_finded("smartdns") then
+ s.fields["smartdns_dns_mode"]:depends({ dns_shunt = "smartdns", tcp_node = v.id })
+ end
+ end
+end
+
+for k, v in pairs(shunt_list) do
+ s.fields["xray_dns_mode"]:depends({ [v.id .. "-type"] = "Xray", tcp_node = v.id })
+ s.fields["singbox_dns_mode"]:depends({ [v.id .. "-type"] = "sing-box", tcp_node = v.id })
+ s.fields["remote_dns_client_ip"]:depends({ tcp_node = v.id })
+ s.fields["remote_fakedns"]:depends({ tcp_node = v.id })
end
m:append(Template(appname .. "/global/footer"))
diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua
index 7399c38..22b18b1 100644
--- a/luci-app-passwall/luasrc/passwall/util_xray.lua
+++ b/luci-app-passwall/luasrc/passwall/util_xray.lua
@@ -1301,6 +1301,7 @@ function gen_config(var)
end
end
+ local dns_rule_position = 1
if dns_listen_port then
table.insert(inbounds, {
listen = "127.0.0.1",
@@ -1334,16 +1335,18 @@ function gen_config(var)
},
outboundTag = "dns-out"
})
+ dns_rule_position = dns_rule_position + 1
end
if COMMON.default_outbound_tag == "direct" then
if direct_dns_udp_server or direct_dns_tcp_server then
- table.insert(routing.rules, {
+ table.insert(routing.rules, dns_rule_position, {
inboundTag = {
"dns-global-direct"
},
outboundTag = "direct"
})
+ dns_rule_position = dns_rule_position + 1
end
end
@@ -1376,11 +1379,12 @@ function gen_config(var)
balancerTag = nil
end
table.insert(dns.servers, dns_server)
- table.insert(routing.rules, {
+ table.insert(routing.rules, dns_rule_position, {
inboundTag = { dns_server.tag },
outboundTag = outboundTag,
balancerTag = balancerTag
})
+ dns_rule_position = dns_rule_position + 1
end
end
end
@@ -1394,11 +1398,12 @@ function gen_config(var)
_outboundTag = "direct"
_balancerTag = nil
end
- table.insert(routing.rules, {
+ table.insert(routing.rules, dns_rule_position, {
inboundTag = { "dns-global" },
balancerTag = _balancerTag,
outboundTag = _outboundTag
})
+ dns_rule_position = dns_rule_position + 1
local default_rule_index = nil
for index, value in ipairs(routing.rules) do
diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po
index 59b47bd..4ee45fa 100644
--- a/luci-app-passwall/po/zh-cn/passwall.po
+++ b/luci-app-passwall/po/zh-cn/passwall.po
@@ -127,9 +127,6 @@ msgstr "您只需要在SmartDNS配置好国内DNS分组,并设置重定向或
msgid "Filter Mode"
msgstr "过滤模式"
-msgid "If the node uses Xray/Sing-Box shunt, select the matching filter mode (Xray/Sing-Box)."
-msgstr "当节点使用 Xray/Sing-Box 分流时,过滤模式需对应选择 Xray/Sing-Box 。"
-
msgid "A/AAAA type"
msgstr "A/AAAA 类型"
diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh
index db6ccbe..2af28dc 100755
--- a/luci-app-passwall/root/usr/share/passwall/app.sh
+++ b/luci-app-passwall/root/usr/share/passwall/app.sh
@@ -2147,24 +2147,6 @@ stop() {
rm -rf /tmp/lock/${CONFIG}_socks_auto_switch*
rm -rf /tmp/lock/${CONFIG}_lease2hosts*
echolog "清空并关闭相关程序和缓存完成。"
- # 根据分流节点类型自动调整 DNS 过滤模式
- local _tcp_node=$(config_t_get global tcp_node)
- if [ -n "$_tcp_node" ]; then
- local _protocol=$(config_n_get $_tcp_node protocol)
- if [ "$_protocol" = "_shunt" ]; then
- local _type=$(config_n_get $_tcp_node type)
- local _dns_mode=$(config_t_get global dns_mode)
- local _new_dns_mode
- [ "$_type" = "Xray" ] && _new_dns_mode="xray"
- [ "$_type" = "sing-box" ] && _new_dns_mode="sing-box"
- if [ -n "$_new_dns_mode" ] && [ "$_dns_mode" != "$_new_dns_mode" ]; then
- uci -q set ${CONFIG}.@global[0].dns_mode="$_new_dns_mode"
- uci -q set ${CONFIG}.@global[0].v2ray_dns_mode="tcp"
- uci -q commit ${CONFIG}
- echolog "* 检测到 TCP 节点为 $_type 分流,强制修改 DNS 过滤模式为 $_type !"
- fi
- fi
- fi
exit 0
}
diff --git a/luci-app-passwall/root/usr/share/passwall/iptables.sh b/luci-app-passwall/root/usr/share/passwall/iptables.sh
index 526ddaf..d1f4fbc 100755
--- a/luci-app-passwall/root/usr/share/passwall/iptables.sh
+++ b/luci-app-passwall/root/usr/share/passwall/iptables.sh
@@ -980,17 +980,20 @@ add_firewall_rule() {
$ipt_n -I PREROUTING 1 -j PSW_DNS
fi
+ $ipt_m -N PSW_DIVERT
+ $ipt_m -A PSW_DIVERT -j MARK --set-mark 1
+ $ipt_m -A PSW_DIVERT -j ACCEPT
+
$ipt_m -N PSW_RULE
$ipt_m -A PSW_RULE -j CONNMARK --restore-mark
$ipt_m -A PSW_RULE -m mark --mark 1 -j RETURN
- $ipt_m -A PSW_RULE -p tcp -m tcp --syn -j MARK --set-xmark 1
- $ipt_m -A PSW_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark 1
+ $ipt_m -A PSW_RULE -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j MARK --set-xmark 1
+ $ipt_m -A PSW_RULE -p udp -m conntrack --ctstate NEW -j MARK --set-xmark 1
$ipt_m -A PSW_RULE -j CONNMARK --save-mark
$ipt_m -N PSW
$ipt_m -A PSW $(dst $IPSET_LAN) -j RETURN
$ipt_m -A PSW $(dst $IPSET_VPS) -j RETURN
- $ipt_m -A PSW -m conntrack --ctdir REPLY -j RETURN
[ ! -z "${WAN_IP}" ] && {
$ipt_m -A PSW $(comment "WAN_IP_RETURN") -d "${WAN_IP}" -j RETURN
@@ -999,11 +1002,11 @@ add_firewall_rule() {
unset WAN_IP
insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW"
+ insert_rule_before "$ipt_m" "PREROUTING" "PSW" "-p tcp -m socket -j PSW_DIVERT"
$ipt_m -N PSW_OUTPUT
$ipt_m -A PSW_OUTPUT $(dst $IPSET_LAN) -j RETURN
$ipt_m -A PSW_OUTPUT $(dst $IPSET_VPS) -j RETURN
- $ipt_m -A PSW_OUTPUT -m conntrack --ctdir REPLY -j RETURN
[ -n "$IPT_APPEND_DNS" ] && {
local local_dns dns_address dns_port
@@ -1050,29 +1053,32 @@ add_firewall_rule() {
$ip6t_n -I PREROUTING 1 -j PSW_DNS
fi
+ $ip6t_m -N PSW_DIVERT
+ $ip6t_m -A PSW_DIVERT -j MARK --set-mark 1
+ $ip6t_m -A PSW_DIVERT -j ACCEPT
+
$ip6t_m -N PSW_RULE
$ip6t_m -A PSW_RULE -j CONNMARK --restore-mark
$ip6t_m -A PSW_RULE -m mark --mark 1 -j RETURN
- $ip6t_m -A PSW_RULE -p tcp -m tcp --syn -j MARK --set-xmark 1
- $ip6t_m -A PSW_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark 1
+ $ip6t_m -A PSW_RULE -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j MARK --set-xmark 1
+ $ip6t_m -A PSW_RULE -p udp -m conntrack --ctstate NEW -j MARK --set-xmark 1
$ip6t_m -A PSW_RULE -j CONNMARK --save-mark
$ip6t_m -N PSW
$ip6t_m -A PSW $(dst $IPSET_LAN6) -j RETURN
$ip6t_m -A PSW $(dst $IPSET_VPS6) -j RETURN
- $ip6t_m -A PSW -m conntrack --ctdir REPLY -j RETURN
WAN6_IP=$(get_wan6_ip)
[ ! -z "${WAN6_IP}" ] && $ip6t_m -A PSW $(comment "WAN6_IP_RETURN") -d ${WAN6_IP} -j RETURN
unset WAN6_IP
insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "-j PSW"
+ insert_rule_before "$ip6t_m" "PREROUTING" "PSW" "-p tcp -m socket -j PSW_DIVERT"
$ip6t_m -N PSW_OUTPUT
$ip6t_m -A PSW_OUTPUT -m mark --mark 0xff -j RETURN
$ip6t_m -A PSW_OUTPUT $(dst $IPSET_LAN6) -j RETURN
$ip6t_m -A PSW_OUTPUT $(dst $IPSET_VPS6) -j RETURN
- $ip6t_m -A PSW_OUTPUT -m conntrack --ctdir REPLY -j RETURN
[ "${USE_BLOCK_LIST}" = "1" ] && $ip6t_m -A PSW_OUTPUT $(dst $IPSET_BLOCK6) -j DROP
[ "${USE_DIRECT_LIST}" = "1" ] && $ip6t_m -A PSW_OUTPUT $(dst $IPSET_WHITE6) -j RETURN
@@ -1309,7 +1315,7 @@ del_firewall_rule() {
$ipt -D $chain $index 2>/dev/null
done
done
- for chain in "PSW" "PSW_OUTPUT" "PSW_DNS" "PSW_RULE"; do
+ for chain in "PSW" "PSW_OUTPUT" "PSW_DIVERT" "PSW_DNS" "PSW_RULE"; do
$ipt -F $chain 2>/dev/null
$ipt -X $chain 2>/dev/null
done
@@ -1363,7 +1369,7 @@ gen_include() {
[ -z "${_ipt}" ] && return
echo "*$2"
- ${_ipt}-save -t $2 | grep "PSW" | grep -v "\-j PSW$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
+ ${_ipt}-save -t $2 | grep "PSW" | grep -v "\-j PSW$" | grep -v "mangle\-OUTPUT\-PSW" | grep -v "socket \-j PSW_DIVERT$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
echo 'COMMIT'
}
local __ipt=""
@@ -1384,6 +1390,7 @@ gen_include() {
[ -z "${is_tproxy}" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p tcp -j PSW")
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW")
+ \$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "PSW" "-p tcp -m socket -j PSW_DIVERT")
WAN_IP=\$(${MY_PATH} get_wan_ip)
@@ -1416,6 +1423,7 @@ gen_include() {
[ "$accept_icmpv6" = "1" ] && $ip6t_n -A PREROUTING -p ipv6-icmp -j PSW
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "-j PSW")
+ \$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "PSW" "-p tcp -m socket -j PSW_DIVERT")
PR_INDEX=\$(${MY_PATH} RULE_LAST_INDEX "$ip6t_m" PSW WAN6_IP_RETURN -1)
if [ \$PR_INDEX -ge 0 ]; then
diff --git a/luci-app-passwall/root/usr/share/passwall/nftables.sh b/luci-app-passwall/root/usr/share/passwall/nftables.sh
index e2db320..e293443 100755
--- a/luci-app-passwall/root/usr/share/passwall/nftables.sh
+++ b/luci-app-passwall/root/usr/share/passwall/nftables.sh
@@ -986,6 +986,10 @@ add_firewall_rule() {
nft_output_chain="PSW_OUTPUT_MANGLE"
fi
+ nft "add chain $NFTABLE_NAME PSW_DIVERT"
+ nft "flush chain $NFTABLE_NAME PSW_DIVERT"
+ nft "add rule $NFTABLE_NAME PSW_DIVERT meta l4proto tcp socket transparent 1 mark set 1 counter accept"
+
nft "add chain $NFTABLE_NAME PSW_DNS"
nft "flush chain $NFTABLE_NAME PSW_DNS"
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
@@ -1001,8 +1005,8 @@ add_firewall_rule() {
nft "flush chain $NFTABLE_NAME PSW_RULE"
nft "add rule $NFTABLE_NAME PSW_RULE meta mark set ct mark counter"
nft "add rule $NFTABLE_NAME PSW_RULE meta mark 1 counter return"
- nft "add rule $NFTABLE_NAME PSW_RULE tcp flags syn meta mark set mark and 0x0 xor 0x1 counter"
- nft "add rule $NFTABLE_NAME PSW_RULE meta l4proto udp ct state new,related meta mark set mark and 0x0 xor 0x1 counter"
+ nft "add rule $NFTABLE_NAME PSW_RULE tcp flags &(fin|syn|rst|ack) == syn meta mark set mark and 0x0 xor 0x1 counter"
+ nft "add rule $NFTABLE_NAME PSW_RULE meta l4proto udp ct state new meta mark set mark and 0x0 xor 0x1 counter"
nft "add rule $NFTABLE_NAME PSW_RULE ct mark set mark counter"
#ipv4 tproxy mode and udp
@@ -1010,13 +1014,11 @@ add_firewall_rule() {
nft "flush chain $NFTABLE_NAME PSW_MANGLE"
nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_LAN counter return"
nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_VPS counter return"
- nft "add rule $NFTABLE_NAME PSW_MANGLE ct direction reply counter return"
nft "add chain $NFTABLE_NAME PSW_OUTPUT_MANGLE"
nft "flush chain $NFTABLE_NAME PSW_OUTPUT_MANGLE"
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_LAN counter return"
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_VPS counter return"
- nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ct direction reply counter return"
[ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_BLOCK counter drop"
[ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_WHITE counter return"
@@ -1025,6 +1027,7 @@ add_firewall_rule() {
# jump chains
nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol udp counter jump PSW_MANGLE"
[ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol tcp counter jump PSW_MANGLE"
+ insert_rule_before "$NFTABLE_NAME" "mangle_prerouting" "PSW_MANGLE" "counter jump PSW_DIVERT"
#ipv4 tcp redirect mode
[ -z "${is_tproxy}" ] && {
@@ -1075,13 +1078,11 @@ add_firewall_rule() {
nft "flush chain $NFTABLE_NAME PSW_MANGLE_V6"
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_LAN6 counter return"
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
- nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ct direction reply counter return"
nft "add chain $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6"
nft "flush chain $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6"
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_LAN6 counter return"
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
- nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ct direction reply counter return"
[ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_BLOCK6 counter drop"
[ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_WHITE6 counter return"
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta mark 0xff counter return"
@@ -1397,7 +1398,7 @@ gen_include() {
local __nft=" "
__nft=$(cat <<- EOF
- [ -z "\$(nft list chain $NFTABLE_NAME mangle_prerouting | grep PSW)" ] && nft -f ${nft_chain_file}
+ [ -z "\$(nft list chain $NFTABLE_NAME mangle_prerouting | grep PSW_DIVERT)" ] && nft -f ${nft_chain_file}
[ -z "${is_tproxy}" ] && {
PR_INDEX=\$(sh ${MY_PATH} RULE_LAST_INDEX "$NFTABLE_NAME" PSW_NAT WAN_IP_RETURN -1)
if [ \$PR_INDEX -ge 0 ]; then
diff --git a/nikki/Makefile b/nikki/Makefile
index 993e4a9..27605ad 100644
--- a/nikki/Makefile
+++ b/nikki/Makefile
@@ -1,15 +1,15 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=nikki
-PKG_VERSION:=2025.10.15
+PKG_VERSION:=2025.11.09
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
-PKG_SOURCE_VERSION:=v1.19.15
-PKG_MIRROR_HASH:=08f97911a7c601eb366c5ab29a7e7ce1f888601d22ed7f357c8732b10a4ec3e2
+PKG_SOURCE_VERSION:=v1.19.16
+PKG_MIRROR_HASH:=35893f8458d21fac840b150d94b8c60e3ce3a50769e196cbcf197f23a070c076
PKG_LICENSE:=GPL3.0+
PKG_MAINTAINER:=Joseph Mory
diff --git a/nikki/files/uci-defaults/migrate.sh b/nikki/files/uci-defaults/migrate.sh
index 1eee74e..4651e56 100644
--- a/nikki/files/uci-defaults/migrate.sh
+++ b/nikki/files/uci-defaults/migrate.sh
@@ -140,12 +140,6 @@ uci show nikki | grep -o -E 'nikki\.@router_access_control\[[[:digit:]]+\]=route
done
done
-# since v1.23.2
-
-env_disable_safe_path_check=$(uci -q get nikki.env.disable_safe_path_check); [ -n "$env_disable_safe_path_check" ] && uci del nikki.env.disable_safe_path_check
-
-env_skip_system_ipv6_check=$(uci -q get nikki.env.skip_system_ipv6_check); [ -z "$env_skip_system_ipv6_check" ] && uci set nikki.env.skip_system_ipv6_check=0
-
# since v1.23.3
uci show nikki | grep -o -E 'nikki\.@router_access_control\[[[:digit:]]+\]=router_access_control' | cut -d '=' -f 1 | while read -r router_access_control; do
diff --git a/nikki/files/ucode/hijack.ut b/nikki/files/ucode/hijack.ut
index 6dce502..8bfe053 100644
--- a/nikki/files/ucode/hijack.ut
+++ b/nikki/files/ucode/hijack.ut
@@ -26,6 +26,7 @@
let dns_listen;
let dns_port;
let fake_ip_range;
+ let fake_ip6_range;
if (profile['dns']) {
dns_listen = profile['dns']['listen'];
const dns_listen_rindex = rindex(dns_listen, ':');
@@ -33,6 +34,7 @@
dns_port = substr(dns_listen, dns_listen_rindex + 1);
}
fake_ip_range = profile['dns']['fake-ip-range'];
+ fake_ip6_range = profile['dns']['fake-ip-range6'];
}
let tun_device;
@@ -445,20 +447,23 @@ table inet nikki {
{% if (tcp_mode == 'redirect'): %}
fib daddr type { local, broadcast, anycast, multicast } counter return
ct direction reply counter return
- ip daddr @reserved_ip counter return
- ip6 daddr @reserved_ip6 counter return
+ ip daddr @reserved_ip {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
+ ip6 daddr @reserved_ip6 {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
- meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
+ meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
- meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
+ meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
meta nfproto @proxy_nfproto jump router_redirect
{% endif %}
{% if (fake_ip_ping_hijack): %}
{% if (fake_ip_range ): %}
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
{% endif %}
+ {% if (fake_ip6_range ): %}
+ icmpv6 type echo-request ip6 daddr {{ fake_ip6_range }} counter redirect
+ {% endif %}
{% endif %}
}
@@ -471,14 +476,14 @@ table inet nikki {
{% endif %}
fib daddr type { local, broadcast, anycast, multicast } counter return
ct direction reply counter return
- ip daddr @reserved_ip counter return
- ip6 daddr @reserved_ip6 counter return
+ ip daddr @reserved_ip {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
+ ip6 daddr @reserved_ip6 {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
- meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
+ meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
- meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
+ meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
{% if (length(dns_hijack_nfproto) > 0): %}
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
{% endif %}
@@ -514,20 +519,23 @@ table inet nikki {
{% if (tcp_mode == 'redirect'): %}
fib daddr type { local, broadcast, anycast, multicast } counter return
ct direction reply counter return
- ip daddr @reserved_ip counter return
- ip6 daddr @reserved_ip6 counter return
+ ip daddr @reserved_ip {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
+ ip6 daddr @reserved_ip6 {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
- meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
+ meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
- meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
+ meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
iifname @lan_inbound_device meta nfproto @proxy_nfproto jump lan_redirect
{% endif %}
{% if (fake_ip_ping_hijack): %}
{% if (fake_ip_range): %}
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
{% endif %}
+ {% if (fake_ip6_range ): %}
+ icmpv6 type echo-request ip6 daddr {{ fake_ip6_range }} counter redirect
+ {% endif %}
{% endif %}
}
@@ -535,14 +543,14 @@ table inet nikki {
type filter hook prerouting priority mangle; policy accept;
fib daddr type { local, broadcast, anycast, multicast } counter return
ct direction reply counter return
- ip daddr @reserved_ip counter return
- ip6 daddr @reserved_ip6 counter return
+ ip daddr @reserved_ip {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
+ ip6 daddr @reserved_ip6 {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
- meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
+ meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
- meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
+ meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
{% if (length(dns_hijack_nfproto) > 0): %}
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
{% endif %}
diff --git a/nikki/files/ucode/mixin.uc b/nikki/files/ucode/mixin.uc
index 9a62611..fecc7c2 100644
--- a/nikki/files/ucode/mixin.uc
+++ b/nikki/files/ucode/mixin.uc
@@ -72,6 +72,7 @@ config['dns']['listen'] = uci.get('nikki', 'mixin', 'dns_listen');
config['dns']['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'dns_ipv6'));
config['dns']['enhanced-mode'] = uci.get('nikki', 'mixin', 'dns_mode');
config['dns']['fake-ip-range'] = uci.get('nikki', 'mixin', 'fake_ip_range');
+config['dns']['fake-ip-range6'] = uci.get('nikki', 'mixin', 'fake_ip6_range');
if (uci_bool(uci.get('nikki', 'mixin', 'fake_ip_filter'))) {
config['dns']['fake-ip-filter'] = uci_array(uci.get('nikki', 'mixin', 'fake_ip_filters'));
}
diff --git a/openwrt-bandix/Makefile b/openwrt-bandix/Makefile
index ad2b613..cfafcf2 100644
--- a/openwrt-bandix/Makefile
+++ b/openwrt-bandix/Makefile
@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=bandix
-PKG_VERSION:=0.6.1
+PKG_VERSION:=0.8.1
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
@@ -13,7 +13,7 @@ include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/rust/rust-values.mk
# 二进制文件的文件名和URL
-RUST_BANDIX_VERSION:=0.6.1
+RUST_BANDIX_VERSION:=0.8.1
RUST_BINARY_FILENAME:=bandix-$(RUST_BANDIX_VERSION)-$(RUSTC_TARGET_ARCH).tar.gz
diff --git a/openwrt-bandix/files/bandix.config b/openwrt-bandix/files/bandix.config
index e3eee29..5ba8e7e 100644
--- a/openwrt-bandix/files/bandix.config
+++ b/openwrt-bandix/files/bandix.config
@@ -20,3 +20,8 @@ config bandix 'traffic'
config bandix 'connections'
option enabled '0'
+
+config bandix 'dns'
+ option enabled '0'
+ option dns_max_records '10000'
+
diff --git a/openwrt-bandix/files/bandix.init b/openwrt-bandix/files/bandix.init
index 78c83f0..e7ab698 100644
--- a/openwrt-bandix/files/bandix.init
+++ b/openwrt-bandix/files/bandix.init
@@ -21,6 +21,8 @@ start_service() {
local traffic_flush_interval_seconds
local traffic_persist_history
local connections_enabled
+ local dns_enabled
+ local dns_max_records
config_load 'bandix'
config_get iface 'general' 'iface'
@@ -31,8 +33,10 @@ start_service() {
config_get traffic_flush_interval_seconds 'traffic' 'traffic_flush_interval_seconds'
config_get_bool traffic_persist_history 'traffic' 'traffic_persist_history'
config_get_bool connections_enabled 'connections' 'enabled'
+ config_get_bool dns_enabled 'dns' 'enabled'
+ config_get dns_max_records 'dns' 'dns_max_records'
- [ "$connections_enabled" != 1 ] && [ "$traffic_enabled" != 1 ] && return 1
+ [ "$connections_enabled" != 1 ] && [ "$traffic_enabled" != 1 ] && [ "$dns_enabled" != 1 ] && return 1
# 构建基础命令行参数
local args="--iface $iface --port $port --data-dir $data_dir"
@@ -56,6 +60,14 @@ start_service() {
args="$args --enable-connection"
fi
+ # 添加 DNS 监控参数
+ if [ "$dns_enabled" -eq 1 ]; then
+ args="$args --enable-dns"
+ fi
+ if [ -n "$dns_max_records" ]; then
+ args="$args --dns-max-records $dns_max_records"
+ fi
+
procd_open_instance bandix
procd_set_param command $PROG $args
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}