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}