Repository: 0xERR0R/blocky (Go)

Issue:
Parse error domains containing xn--
Upgraded to 0.22 (skipped 0.21 due to the parsing rework) but now the parsing of blocklist fail when it finds domains containing `xn--`. For example using blocklist `https://big.oisd.nl/regex` the following errors are shown:

```
[2023-09-02 16:45:58]  WARN list_cache: parse error: line 2592: 2 errors occurred:
	* idna: invalid label "aptslabs-6fd\\": /^(.*\.)?2023\.xn--aptslabs-6fd\.net$/
	* invalid ip: /^(.*\.)?2023\.xn--aptslabs-6fd\.net$/

, trying to continue count=2580 source=https://big.oisd.nl/regex
[2023-09-02 16:45:59]  WARN list_cache: parse error: line 13224: 2 errors occurred:
	* idna: invalid label "futuroenespaol-1nb\\": /^(.*\.)?adbmetrics\.xn--futuroenespaol-1nb\.es$/
	* invalid ip: /^(.*\.)?adbmetrics\.xn--futuroenespaol-1nb\.es$/

, trying to continue count=13211 source=https://big.oisd.nl/regex
[2023-09-02 16:46:00]  WARN list_cache: parse error: line 33199: 2 errors occurred:
	* idna: invalid label "55qx5d\\": /^(.*\.)?autodiscover\.xn--55qx5d\.cn$/
	* invalid ip: /^(.*\.)?autodiscover\.xn--55qx5d\.cn$/

, trying to continue count=33185 source=https://big.oisd.nl/regex
[2023-09-02 16:46:00]  WARN list_cache: parse error: line 33200: 2 errors occurred:
	* idna: invalid label "90amc\\": /^(.*\.)?autodiscover\.xn--90amc\.xn--p1acf$/
	* invalid ip: /^(.*\.)?autodiscover\.xn--90amc\.xn--p1acf$/

, trying to continue count=33185 source=https://big.oisd.nl/regex
[2023-09-02 16:46:00]  WARN list_cache: parse error: line 33201: 2 errors occurred:
	* idna: invalid label "gnstigbestellen-zvb\\": /^(.*\.)?autodiscover\.xn--gnstigbestellen-zvb\.de$/
	* invalid ip: /^(.*\.)?autodiscover\.xn--gnstigbestellen-zvb\.de$/

, trying to continue count=33185 source=https://big.oisd.nl/regex

```


Discussion:
I can reproduce this error. We're trying to convert the hostname from puny code to ASCII, even if it is a regex. I changed this behavior: regex will not be converted. @ThinkChaos please check, if it is ok :)



Patch:
diff --git a/lists/parsers/hosts.go b/lists/parsers/hosts.go
index 67ef77f9a..1cba0a3f0 100644
--- a/lists/parsers/hosts.go
+++ b/lists/parsers/hosts.go
@@ -201,15 +201,18 @@ func (e HostsFileEntry) forEachHost(callback func(string) error) error {
 }
 
 func normalizeHostsListEntry(host string) (string, error) {
+	var err error
 	// Lookup is the profile preferred for DNS queries, we use Punycode here as it does less validation.
 	// That avoids rejecting domains in a list for reasons that amount to "that domain should not be used"
 	// since the goal of the list is to determine whether the domain should be used or not, we leave
 	// that decision to it.
 	idnaProfile := idna.Punycode
 
-	host, err := idnaProfile.ToASCII(host)
-	if err != nil {
-		return "", fmt.Errorf("%w: %s", err, host)
+	if !isRegex(host) {
+		host, err = idnaProfile.ToASCII(host)
+		if err != nil {
+			return "", fmt.Errorf("%w: %s", err, host)
+		}
 	}
 
 	if err := validateHostsListEntry(host); err != nil {
@@ -231,12 +234,16 @@ func validateDomainName(host string) error {
 	return fmt.Errorf("invalid domain name: %s", host)
 }
 
+func isRegex(host string) bool {
+	return strings.HasPrefix(host, "/") && strings.HasSuffix(host, "/")
+}
+
 func validateHostsListEntry(host string) error {
 	if net.ParseIP(host) != nil {
 		return nil
 	}
 
-	if strings.HasPrefix(host, "/") && strings.HasSuffix(host, "/") {
+	if isRegex(host) {
 		_, err := regexp.Compile(host)
 
 		return err


Test patch:
diff --git a/lists/parsers/hosts_test.go b/lists/parsers/hosts_test.go
index 0d6e51141..3f10433e5 100644
--- a/lists/parsers/hosts_test.go
+++ b/lists/parsers/hosts_test.go
@@ -34,6 +34,8 @@ var _ = Describe("Hosts", func() {
 				"127.0.0.1 domain.tld # comment",
 				"::1 localhost alias",
 				`/domain\.(tld|local)/`,
+				`/^(.*\.)?2023\.xn--aptslabs-6fd\.net$/`,
+				`müller.com`,
 			)
 		})
 
@@ -58,11 +60,21 @@ var _ = Describe("Hosts", func() {
 			Expect(iteratorToList(it.ForEach)).Should(Equal([]string{`/domain\.(tld|local)/`}))
 			Expect(sut.Position()).Should(Equal("line 6"))
 
+			it, err = sut.Next(context.Background())
+			Expect(err).Should(Succeed())
+			Expect(iteratorToList(it.ForEach)).Should(Equal([]string{`/^(.*\.)?2023\.xn--aptslabs-6fd\.net$/`}))
+			Expect(sut.Position()).Should(Equal("line 7"))
+
+			it, err = sut.Next(context.Background())
+			Expect(err).Should(Succeed())
+			Expect(iteratorToList(it.ForEach)).Should(Equal([]string{`xn--mller-kva.com`}))
+			Expect(sut.Position()).Should(Equal("line 8"))
+
 			_, err = sut.Next(context.Background())
 			Expect(err).ShouldNot(Succeed())
 			Expect(err).Should(MatchError(io.EOF))
 			Expect(IsNonResumableErr(err)).Should(BeTrue())
-			Expect(sut.Position()).Should(Equal("line 7"))
+			Expect(sut.Position()).Should(Equal("line 9"))
 		})
 	})
 
@@ -71,6 +83,7 @@ var _ = Describe("Hosts", func() {
 			lines := []string{
 				"invalidIP localhost",
 				"!notadomain!",
+				"xn---mllerk1va.com",
 				`/invalid regex ??/`,
 			}