diff options
Diffstat (limited to 'netwerk/dns/nsIDNService.cpp')
-rw-r--r-- | netwerk/dns/nsIDNService.cpp | 98 |
1 files changed, 78 insertions, 20 deletions
diff --git a/netwerk/dns/nsIDNService.cpp b/netwerk/dns/nsIDNService.cpp index 3db169d3af..6a87c8ee06 100644 --- a/netwerk/dns/nsIDNService.cpp +++ b/netwerk/dns/nsIDNService.cpp @@ -10,6 +10,8 @@ #include "nsReadableUtils.h" #include "nsCRT.h" #include "nsServiceManagerUtils.h" +#include "nsString.h" +#include "nsStringFwd.h" #include "nsUnicharUtils.h" #include "nsUnicodeProperties.h" #include "harfbuzz/hb.h" @@ -286,12 +288,35 @@ nsresult nsIDNService::ACEtoUTF8(const nsACString& input, nsACString& _retval, input.EndReading(end); _retval.Truncate(); + if (input.IsEmpty()) { + return NS_OK; + } + + nsAutoCString tld; + nsCString::const_iterator it = end, tldEnd = end; + --it; + if (it != start && *it == (char16_t)'.') { + // This is an FQDN (ends in .) + // Skip this dot to extract the TLD + tldEnd = it; + --it; + } + // Find last . and compute TLD + while (it != start) { + if (*it == (char16_t)'.') { + ++it; + tld.Assign(Substring(it, tldEnd)); + break; + } + --it; + } + // loop and decode nodes while (start != end) { len++; if (*start++ == '.') { nsDependentCSubstring origLabel(input, offset, len - 1); - if (NS_FAILED(decodeACE(origLabel, decodedBuf, flag))) { + if (NS_FAILED(decodeACE(origLabel, decodedBuf, flag, tld))) { // If decoding failed, use the original input sequence // for this label. _retval.Append(origLabel); @@ -307,7 +332,7 @@ nsresult nsIDNService::ACEtoUTF8(const nsACString& input, nsACString& _retval, // decode the last node if (len) { nsDependentCSubstring origLabel(input, offset, len); - if (NS_FAILED(decodeACE(origLabel, decodedBuf, flag))) { + if (NS_FAILED(decodeACE(origLabel, decodedBuf, flag, tld))) { _retval.Append(origLabel); } else { _retval.Append(decodedBuf); @@ -343,8 +368,7 @@ NS_IMETHODIMP nsIDNService::IsACE(const nsACString& input, bool* _retval) { return NS_OK; } -NS_IMETHODIMP nsIDNService::Normalize(const nsACString& input, - nsACString& output) { +nsresult nsIDNService::Normalize(const nsACString& input, nsACString& output) { // protect against bogus input NS_ENSURE_TRUE(IsUtf8(input), NS_ERROR_UNEXPECTED); @@ -562,7 +586,7 @@ nsresult nsIDNService::stringPrepAndACE(const nsAString& in, nsACString& out, return NS_OK; } - if (flag == eStringPrepForUI && NS_SUCCEEDED(rv) && isLabelSafe(in)) { + if (flag == eStringPrepForUI && NS_SUCCEEDED(rv) && isLabelSafe(in, u""_ns)) { CopyUTF16toUTF8(strPrep, out); return NS_OK; } @@ -598,7 +622,7 @@ void nsIDNService::normalizeFullStops(nsAString& s) { } nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out, - stringPrepFlag flag) { + stringPrepFlag flag, const nsACString& aTLD) { bool isAce; IsACE(in, &isAce); if (!isAce) { @@ -610,7 +634,9 @@ nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out, nsresult result = IDNA2008ToUnicode(in, utf16); NS_ENSURE_SUCCESS(result, result); - if (flag != eStringPrepForUI || isLabelSafe(utf16)) { + NS_ConvertUTF8toUTF16 tld(aTLD); + + if (flag != eStringPrepForUI || isLabelSafe(utf16, tld)) { CopyUTF16toUTF8(utf16, out); } else { out.Assign(in); @@ -652,17 +678,21 @@ enum ScriptCombo : int32_t { } // namespace mozilla::net -bool nsIDNService::isLabelSafe(const nsAString& label) { - AutoReadLock lock(mLock); +bool nsIDNService::isLabelSafe(const nsAString& label, const nsAString& tld) { + restrictionProfile profile{eASCIIOnlyProfile}; + { + AutoReadLock lock(mLock); - if (!isOnlySafeChars(PromiseFlatString(label), mIDNBlocklist)) { - return false; - } + if (!isOnlySafeChars(PromiseFlatString(label), mIDNBlocklist)) { + return false; + } - // We should never get here if the label is ASCII - NS_ASSERTION(!IsAscii(label), "ASCII label in IDN checking"); - if (mRestrictionProfile == eASCIIOnlyProfile) { - return false; + // We should never get here if the label is ASCII + NS_ASSERTION(!IsAscii(label), "ASCII label in IDN checking"); + if (mRestrictionProfile == eASCIIOnlyProfile) { + return false; + } + profile = mRestrictionProfile; } nsAString::const_iterator current, end; @@ -697,7 +727,7 @@ bool nsIDNService::isLabelSafe(const nsAString& label) { Script script = UnicodeProperties::GetScriptCode(ch); if (script != Script::COMMON && script != Script::INHERITED && script != lastScript) { - if (illegalScriptCombo(script, savedScript)) { + if (illegalScriptCombo(profile, script, savedScript)) { return false; } } @@ -708,11 +738,39 @@ bool nsIDNService::isLabelSafe(const nsAString& label) { return false; } + Script nextScript = Script::INVALID; + if (current != end) { + nextScript = UnicodeProperties::GetScriptCode(*current); + } + + if (ch == 0x30FB && + (lastScript == Script::LATIN || nextScript == Script::LATIN)) { + return false; + } + if (ch == 0x307 && (previousChar == 'i' || previousChar == 'j' || previousChar == 'l')) { return false; } + // U+00B7 is only allowed on Catalan domains between two l's. + if (ch == 0xB7 && (!tld.EqualsLiteral("cat") || previousChar != 'l' || + current == end || *current != 'l')) { + return false; + } + + // Disallow Icelandic confusables for domains outside Icelandic and Faroese + // ccTLD (.is, .fo) + if ((ch == 0xFE || ch == 0xF0) && !tld.EqualsLiteral("is") && + !tld.EqualsLiteral("fo")) { + return false; + } + + // Block single/double-quote-like characters. + if (ch == 0x2BB || ch == 0x2BC) { + return false; + } + // Check for mixed numbering systems auto genCat = GetGeneralCategory(ch); if (genCat == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) { @@ -834,7 +892,8 @@ static const ScriptCombo scriptComboTable[13][9] = { /* KORE */ {FAIL, FAIL, FAIL, KORE, KORE, FAIL, FAIL, KORE, FAIL}, /* HNLT */ {CHNA, FAIL, FAIL, KORE, HNLT, JPAN, JPAN, HNLT, FAIL}}; -bool nsIDNService::illegalScriptCombo(Script script, ScriptCombo& savedScript) { +bool nsIDNService::illegalScriptCombo(restrictionProfile profile, Script script, + ScriptCombo& savedScript) { if (savedScript == ScriptCombo::UNSET) { savedScript = findScriptIndex(script); return false; @@ -849,7 +908,6 @@ bool nsIDNService::illegalScriptCombo(Script script, ScriptCombo& savedScript) { * In the Moderately Restrictive profile Latin mixed with any other * single script is allowed. */ - return ((savedScript == OTHR && - mRestrictionProfile == eHighlyRestrictiveProfile) || + return ((savedScript == OTHR && profile == eHighlyRestrictiveProfile) || savedScript == FAIL); } |