Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 80 additions & 20 deletions dcc-network/operation/dccnetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,32 +65,92 @@ void DccNetwork::exec(NetManager::CmdType cmd, const QString &id, const QVariant
const QVariantList &dnsData = ipData.value("dns").toList();
QList<uint> dns;
for (auto it : dnsData) {
dns.append(it.toUInt());
// 支持两种DNS格式:数字格式(IPv4)和字符串格式(IPv6)
if (it.type() == QVariant::UInt || it.type() == QVariant::Int) {
dns.append(it.toUInt());
} else if (it.type() == QVariant::String) {
QString dnsStr = it.toString();
if (!dnsStr.isEmpty()) {
// IPv6地址需要通过QHostAddress转换为数字表示
QHostAddress addr(dnsStr);
if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
// IPv4字符串转换为数字
dns.append(addr.toIPv4Address());
} else if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
// IPv6地址转换为128位表示(当前系统可能不支持,先跳过)
qWarning() << "IPv6 DNS not fully implemented in backend, DNS:" << dnsStr;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: IPv6 DNS handling is unimplemented and skipped

If IPv6 DNS support is needed, please implement full handling or add a fallback to avoid skipped records.

// 这里需要实现IPv6 DNS的完整支持
}
}
}
}
ipData["dns"] = QVariant::fromValue(dns);
}
tmpParam["ipv4"] = QVariant::fromValue(ipData);
}
if (param.contains("ipv6") && param.value("ipv6").toMap().contains("address-data")) {
const QVariantList &addressData = param.value("ipv6").toMap().value("address-data").toList();
QString gatewayStr = param.value("ipv6").toMap().value("gateway").toString();
IpV6DBusAddressList ipv6AddressList;
for (auto it : addressData) {
IpV6DBusAddress ipv6Address;
QVariantMap ipv6Data = it.toMap();
QHostAddress ip(ipv6Data.value("address").toString());
QIPv6Address ipv6Addr = ip.toIPv6Address();
QByteArray tmpAddress((char *)(ipv6Addr.c), 16);
ipv6Address.address = tmpAddress;
ipv6Address.prefix = ipv6Data.value("prefix").toUInt();
QHostAddress gateway(ipv6AddressList.isEmpty() ? gatewayStr : QString());
QByteArray tmpGateway((char *)(gateway.toIPv6Address().c), 16);
ipv6Address.gateway = tmpGateway;
ipv6AddressList.append(ipv6Address);
if (param.contains("ipv6")) {
QVariantMap ipv6Data = param.value("ipv6").toMap();

// 处理IPv6地址
if (ipv6Data.contains("address-data")) {
const QVariantList &addressData = ipv6Data.value("address-data").toList();
QString gatewayStr = ipv6Data.value("gateway").toString();
IpV6DBusAddressList ipv6AddressList;
for (auto it : addressData) {
IpV6DBusAddress ipv6Address;
QVariantMap ipv6AddrData = it.toMap();
QHostAddress ip(ipv6AddrData.value("address").toString());
QIPv6Address ipv6Addr = ip.toIPv6Address();
QByteArray tmpAddress((char *)(ipv6Addr.c), 16);
ipv6Address.address = tmpAddress;
ipv6Address.prefix = ipv6AddrData.value("prefix").toUInt();
QHostAddress gateway(ipv6AddressList.isEmpty() ? gatewayStr : QString());
QByteArray tmpGateway((char *)(gateway.toIPv6Address().c), 16);
ipv6Address.gateway = tmpGateway;
ipv6AddressList.append(ipv6Address);
}
ipv6Data["addresses"] = QVariant::fromValue(ipv6AddressList);
}

// 处理IPv6 DNS
if (ipv6Data.contains("dns")) {
const QVariantList &dnsData = ipv6Data.value("dns").toList();
QList<QHostAddress> ipv6DnsAddresses;
for (auto it : dnsData) {
if (it.type() == QVariant::String) {
QString dnsStr = it.toString();
if (!dnsStr.isEmpty()) {
QHostAddress addr(dnsStr);
if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
ipv6DnsAddresses.append(addr);
}
}
}
}
if (!ipv6DnsAddresses.isEmpty()) {
// 直接使用字符串列表格式 - NetworkManager配置文件实际存储字符串
QStringList ipv6DnsStrings;
for (const QHostAddress &addr : ipv6DnsAddresses) {
ipv6DnsStrings.append(addr.toString());
}

// 使用字符串列表格式保存IPv6 DNS
ipv6Data["dns"] = ipv6DnsStrings;
ipv6Data["ignore-auto-dns"] = true;
} else {
// 没有有效的IPv6 DNS时,确保移除ignore-auto-dns设置
// 这样系统可以恢复自动获取DNS
ipv6Data.remove("dns");
ipv6Data.remove("ignore-auto-dns");
}

// 确保IPv6设置存在,即使没有DNS也要设置,以便被正确处理
if (ipv6Data.isEmpty()) {
ipv6Data["method"] = "auto"; // 至少设置一个值确保IPv6部分存在
}
}
QVariantMap ipData = param.value("ipv6").toMap();
ipData["addresses"] = QVariant::fromValue(ipv6AddressList);
tmpParam["ipv6"] = QVariant::fromValue(ipData);

tmpParam["ipv6"] = QVariant::fromValue(ipv6Data);
}
m_manager->exec(cmd, id, tmpParam);
} break;
Expand Down
75 changes: 52 additions & 23 deletions dcc-network/qml/NetUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,37 @@ const maskRegExp = /(254|252|248|240|224|192|128|0)\.0\.0\.0|255\.(254|252|248|2
// MAC正则表达式
const macRegExp = /([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})/

// 验证IP地址是否为IPv4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider refactoring the three IP address validation functions into a single, data-driven validator with optional debug logging.

You can collapse the three new `isIpv4Address`/`isIpv6Address`/`isValidIpAddress` functions into a single, data-driven validator and drop all the repetitive `console.log` calls (or guard them behind a `DEBUG` flag). For example:

```js
// keep your existing regexes
const ipRegexList = [
  { name: 'IPv4', re: ipRegExp },
  { name: 'IPv6', re: ipv6RegExp }
];

// single validator
function isValidIpAddress(ip, { debug = false } = {}) {
  const results = ipRegexList.map(({name, re}) => {
    const ok = re.test(ip);
    if (debug) console.log(`[IP-Validation] ${name}`, ip, ok);
    return ok;
  });
  const final = results.some(Boolean);
  if (debug) console.log(`[IP-Validation] FINAL`, ip, final);
  return final;
}

Then remove the old isIpv4Address, isIpv6Address definitions entirely. If you still want to expose them:

const isIpv4Address = ip => isValidIpAddress(ip) && ipRegExp.test(ip);
const isIpv6Address = ip => isValidIpAddress(ip) && ipv6RegExp.test(ip);

But in most cases you only need isValidIpAddress. This cuts ~50 lines, centralizes the logic, and makes it trivial to toggle debug logs.

function isIpv4Address(ip) {
const result = ipRegExp.test(ip)
console.log("[IPv4-Validation] Validating IPv4:", ip, "Result:", result)
return result
}

// 验证IP地址是否为IPv6
function isIpv6Address(ip) {
const result = ipv6RegExp.test(ip)
console.log("[IPv6-Validation] Validating IPv6:", ip, "Result:", result)
return result
}

// 验证IP地址(同时支持IPv4和IPv6)
function isValidIpAddress(ip) {
const ipv4Result = isIpv4Address(ip)
const ipv6Result = isIpv6Address(ip)
const finalResult = ipv4Result || ipv6Result
console.log("[IP-Validation] Validating IP:", ip, "IPv4:", ipv4Result, "IPv6:", ipv6Result, "Final:", finalResult)
return finalResult
}

function toVpnTypeEnum(vpnKey) {
let key = vpnKey.substring(31)
const key = vpnKey.substring(31)
console.log("toVpnTypeEnum", vpnKey, key)
return VpnTypeEnum.hasOwnProperty(key) ? VpnTypeEnum[key] : 0x01
}

function toVpnKey(vpnType) {
for (let key in VpnTypeEnum) {
for (const key in VpnTypeEnum) {
if (VpnTypeEnum[key] === vpnType) {
return "org.freedesktop.NetworkManager." + key
}
Expand All @@ -39,23 +62,24 @@ function removeTrailingNull(str) {
}

function numToIp(num) {
let ips = [0, 0, 0, 0]
for (var i = 0; i < 4; i++) {
const ips = [0, 0, 0, 0]
for (let i = 0; i < 4; i++) {
ips[i] = (num >> (i * 8)) & 255
}
return ips.join('.')
}

function ipToNum(ip) {
console.log("ipToNum----", ip, typeof ip)
let ips = ip.split('.')
const ips = ip.split('.')
let cidr = 0
let ipNum = 0
if (ips.length !== 4) {
return 0
}
for (let ipStr of ips) {
let num = parseInt(ipStr, 10)
for (let i = 0; i < ips.length; i++) {
const ipStr = ips[i]
const num = parseInt(ipStr, 10)
ipNum |= ((num & 255) << cidr)
cidr += 8
}
Expand All @@ -67,10 +91,10 @@ function prefixToIp(subnetMask) {
throw new Error("Subnet mask must be between 0 and 32")
}

let maskArray = [255, 255, 255, 255]
const maskArray = [255, 255, 255, 255]

for (var i = 0; i < 4; i++) {
let byteBits = i * 8 + 8 - subnetMask
for (let i = 0; i < 4; i++) {
const byteBits = i * 8 + 8 - subnetMask
if (byteBits > 0) {
maskArray[i] = (255 << byteBits) & 255
}
Expand All @@ -80,12 +104,13 @@ function prefixToIp(subnetMask) {
}

function ipToPrefix(decimalSubnet) {
let octets = decimalSubnet.split('.')
const octets = decimalSubnet.split('.')
let cidr = 0

for (let octet of octets) {
let num = parseInt(octet, 10)
for (var i = 0; i < 8; i++) {
for (let j = 0; j < octets.length; j++) {
const octet = octets[j]
const num = parseInt(octet, 10)
for (let i = 0; i < 8; i++) {
if ((num & (1 << (7 - i))) !== 0) {
cidr++
} else {
Expand All @@ -99,22 +124,26 @@ function ipToPrefix(decimalSubnet) {
}

function macToStr(mac) {
return Array.prototype.map.call(new Uint8Array(mac), x => ('00' + x.toString(16)).toUpperCase().slice(-2)).join(':')
return Array.prototype.map.call(new Uint8Array(mac), function(x) {
return ('00' + x.toString(16)).toUpperCase().slice(-2)
}).join(':')
}

function strToMac(str) {
if (str.length === 0)
return new Uint8Array()
let arr = str.split(":")
let hexArr = arr.join("")
return new Uint8Array(hexArr.match(/[\da-f]{2}/gi).map(bb => {
return parseInt(bb, 16)
})).buffer
const arr = str.split(":")
const hexArr = arr.join("")
return new Uint8Array(hexArr.match(/[\da-f]{2}/gi).map(function(bb) {
return parseInt(bb, 16)
})).buffer
}

// 转为ByteArray并以\0结尾
function strToByteArray(data) {
if (typeof data === 'string') {
var arr = []
for (var i = 0; i < data.length; ++i) {
const arr = []
for (let i = 0; i < data.length; ++i) {
let charcode = data.charCodeAt(i)
if (charcode < 0x80) {
arr.push(charcode)
Expand All @@ -125,7 +154,7 @@ function strToByteArray(data) {
} else {
// Handle surrogate pairs (U+10000 to U+10FFFF)
i++
charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff))
charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (data.charCodeAt(i) & 0x3ff))
arr.push(0xf0 | (charcode >> 18), 0x80 | ((charcode >> 12) & 0x3f), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f))
}
}
Expand Down
37 changes: 35 additions & 2 deletions dcc-network/qml/PageDSLSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,15 @@ DccObject {
sectionGeneric.setConfig(config.connection)
sectionPPPOE.setConfig(config["pppoe"])
sectionIPv4.setConfig(config.ipv4)
sectionDNS.setConfig((config.hasOwnProperty("ipv4") && config.ipv4.hasOwnProperty("dns")) ? config.ipv4.dns : null)
// 合并IPv4和IPv6的DNS配置
let combinedDns = []
if (config.hasOwnProperty("ipv4") && config.ipv4.hasOwnProperty("dns") && config.ipv4.dns.length > 0) {
combinedDns = combinedDns.concat(config.ipv4.dns)
}
if (config.hasOwnProperty("ipv6") && config.ipv6.hasOwnProperty("dns") && config.ipv6.dns.length > 0) {
combinedDns = combinedDns.concat(config.ipv6.dns)
}
sectionDNS.setConfig(combinedDns.length > 0 ? combinedDns : null)
sectionDevice.setConfig(config["802-3-ethernet"])
sectionPPP.setConfig(config["ppp"])
modified = config.connection.uuid === "{00000000-0000-0000-0000-000000000000}"
Expand Down Expand Up @@ -192,7 +200,32 @@ DccObject {
if (nConfig["ipv4"] === undefined) {
nConfig["ipv4"] = {}
}
nConfig["ipv4"]["dns"] = sectionDNS.getConfig()

// 获取DNS配置并分离IPv4和IPv6
let dnsConfig = sectionDNS.getConfig()
let ipv4Dns = []
let ipv6Dns = []

for (let dns of dnsConfig) {
if (typeof dns === 'number') {
// IPv4 DNS(数字格式)
ipv4Dns.push(dns)
} else if (typeof dns === 'string') {
// IPv6 DNS(字符串格式)
ipv6Dns.push(dns)
}
}

// 保存IPv4 DNS
nConfig["ipv4"]["dns"] = ipv4Dns

// 如果有IPv6 DNS,也要保存
if (ipv6Dns.length > 0) {
if (!nConfig["ipv6"]) {
nConfig["ipv6"] = {}
}
nConfig["ipv6"]["dns"] = ipv6Dns
}
let devConfig = sectionDevice.getConfig()
if (devConfig.interfaceName.length !== 0) {
nConfig["pppoe"]["parent"] = devConfig.interfaceName
Expand Down
33 changes: 31 additions & 2 deletions dcc-network/qml/PageSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@ DccObject {
sectionSecret.setConfig802_1x(config["802-1x"])
sectionIPv4.setConfig(config.ipv4)
sectionIPv6.setConfig(config.ipv6)
sectionDNS.setConfig((config.hasOwnProperty("ipv4") && config.ipv4.hasOwnProperty("dns")) ? config.ipv4.dns : null)
// 合并IPv4和IPv6的DNS配置
let combinedDns = []
if (config.hasOwnProperty("ipv4") && config.ipv4.hasOwnProperty("dns") && config.ipv4.dns.length > 0) {
combinedDns = combinedDns.concat(config.ipv4.dns)
}
if (config.hasOwnProperty("ipv6") && config.ipv6.hasOwnProperty("dns") && config.ipv6.dns.length > 0) {
combinedDns = combinedDns.concat(config.ipv6.dns)
}
sectionDNS.setConfig(combinedDns.length > 0 ? combinedDns : null)
sectionDevice.type = type
sectionDevice.setConfig(config[config.connection.type])
modified = config.connection.uuid === "{00000000-0000-0000-0000-000000000000}" && sectionGeneric.settingsID.length !== 0
Expand Down Expand Up @@ -197,7 +205,28 @@ DccObject {
if (nConfig["ipv4"] === undefined) {
nConfig["ipv4"] = {}
}
nConfig["ipv4"]["dns"] = sectionDNS.getConfig()
if (nConfig["ipv6"] === undefined) {
nConfig["ipv6"] = {}
}

// 获取DNS配置并分离IPv4和IPv6
let dnsConfig = sectionDNS.getConfig()
let ipv4Dns = []
let ipv6Dns = []

for (let dns of dnsConfig) {
if (typeof dns === 'number') {
// IPv4 DNS(数字格式)
ipv4Dns.push(dns)
} else if (typeof dns === 'string') {
// IPv6 DNS(字符串格式)
ipv6Dns.push(dns)
}
}

// 分别保存到IPv4和IPv6配置中
nConfig["ipv4"]["dns"] = ipv4Dns
nConfig["ipv6"]["dns"] = ipv6Dns
let devConfig = sectionDevice.getConfig()
if (devConfig.interfaceName.length === 0) {
delete nConfig["connection"]["interface-name"]
Expand Down
Loading