git » chasquid » commit 8f1f943

mda-lmtp: Add -to_puny, to punycode-encode addresses

author Alberto Bertogli
2021-06-25 11:09:56 UTC
committer Alberto Bertogli
2021-06-25 11:15:42 UTC
parent f137702f238f55e70e4d39d99b44e4a1db07b0bf

mda-lmtp: Add -to_puny, to punycode-encode addresses

Some LMTP servers (like dovecot) can't handle UTF8 addresses in the LMTP
commands. This can be problematic if we want to use them with UTF8
domains or usernames, which are well supported by chasquid.

To help workaround this issue, this patch adds a new -to_puny flag for
mda-lmtp, that makes it encode `from` and `recipient` in punycode.

That way, the server will get punycode-encoded (ASCII) strings in the
LTMP commands.

This can be particularly convenient when the recipients are ASCII
(because they're under the mail server control), but `from` may not be
(because it comes from the network).

cmd/mda-lmtp/mda-lmtp.go +23 -2
cmd/mda-lmtp/test_puny_ascii.cmy +33 -0
cmd/mda-lmtp/test_puny_invalid.cmy +9 -0
cmd/mda-lmtp/test_puny_utf8.cmy +33 -0
cmd/mda-lmtp/test_utf8.cmy +33 -0

diff --git a/cmd/mda-lmtp/mda-lmtp.go b/cmd/mda-lmtp/mda-lmtp.go
index 8be8bfa..5c1a699 100644
--- a/cmd/mda-lmtp/mda-lmtp.go
+++ b/cmd/mda-lmtp/mda-lmtp.go
@@ -14,6 +14,8 @@ import (
 	"net/textproto"
 	"os"
 	"strings"
+
+	"golang.org/x/net/idna"
 )
 
 // Command-line flags
@@ -24,6 +26,9 @@ var (
 	addrNetwork = flag.String("addr_network", "",
 		"Network of the LMTP address (e.g. unix or tcp)")
 	addr = flag.String("addr", "", "LMTP server address")
+
+	toPuny = flag.Bool("to_puny", false,
+		"Encode addresses using punycode")
 )
 
 func usage() {
@@ -51,13 +56,29 @@ func tempExit(format string, args ...interface{}) {
 	os.Exit(75)
 }
 
+func permExit(format string, args ...interface{}) {
+	fmt.Printf(format+"\n", args...)
+	os.Exit(2)
+}
+
 func main() {
+	var err error
 	flag.Usage = usage
 	flag.Parse()
 
 	if *addr == "" {
-		fmt.Printf("No LMTP server address given (use --addr)\n")
-		os.Exit(2)
+		permExit("No LMTP server address given (use --addr)")
+	}
+
+	if *toPuny {
+		*fromwhom, err = idna.ToASCII(*fromwhom)
+		if err != nil {
+			permExit("cannot puny-encode from: %v", err)
+		}
+		*recipient, err = idna.ToASCII(*recipient)
+		if err != nil {
+			permExit("cannot puny-encode recipient: %v", err)
+		}
 	}
 
 	// Try to autodetect the network if it's missing.
diff --git a/cmd/mda-lmtp/test_puny_ascii.cmy b/cmd/mda-lmtp/test_puny_ascii.cmy
new file mode 100644
index 0000000..9998e6c
--- /dev/null
+++ b/cmd/mda-lmtp/test_puny_ascii.cmy
@@ -0,0 +1,33 @@
+
+nc unix_listen .test-sock
+
+mda |= ./mda-lmtp --addr=.test-sock --addr_network=unix \
+        -to_puny -f from -d to < test-email
+
+nc -> 220 Hola desde expect
+
+nc <~ LHLO .*
+nc -> 250-Bienvenido!
+nc -> 250 Contame...
+
+nc <- MAIL FROM:<from>
+nc -> 250 Aja
+
+nc <- RCPT TO:<to>
+nc -> 250 Aja
+
+nc <- DATA
+nc -> 354 Dale
+
+nc <- Subject: test
+nc <-
+nc <- This is a test.
+nc <- .
+
+nc -> 250 Recibido
+
+nc <- QUIT
+nc -> 221 Chauchas
+
+mda wait 0
+
diff --git a/cmd/mda-lmtp/test_puny_invalid.cmy b/cmd/mda-lmtp/test_puny_invalid.cmy
new file mode 100644
index 0000000..9c63706
--- /dev/null
+++ b/cmd/mda-lmtp/test_puny_invalid.cmy
@@ -0,0 +1,9 @@
+mda = ./mda-lmtp --addr=.test-sock --addr_network=unix \
+        -to_puny -f fröm -d xn--t < test-email
+mda <- cannot puny-encode recipient: idna: invalid label "t"
+mda wait 2
+
+mda = ./mda-lmtp --addr=.test-sock --addr_network=unix \
+        -to_puny -f xn--f -d to < test-email
+mda <- cannot puny-encode from: idna: invalid label "f"
+mda wait 2
diff --git a/cmd/mda-lmtp/test_puny_utf8.cmy b/cmd/mda-lmtp/test_puny_utf8.cmy
new file mode 100644
index 0000000..852aa4f
--- /dev/null
+++ b/cmd/mda-lmtp/test_puny_utf8.cmy
@@ -0,0 +1,33 @@
+
+nc unix_listen .test-sock
+
+mda |= ./mda-lmtp --addr=.test-sock --addr_network=unix \
+        -to_puny -f fröm -d þo < test-email
+
+nc -> 220 Hola desde expect
+
+nc <~ LHLO .*
+nc -> 250-Bienvenido!
+nc -> 250 Contame...
+
+nc <- MAIL FROM:<xn--frm-tna>
+nc -> 250 Aja
+
+nc <- RCPT TO:<xn--o-hha>
+nc -> 250 Aja
+
+nc <- DATA
+nc -> 354 Dale
+
+nc <- Subject: test
+nc <-
+nc <- This is a test.
+nc <- .
+
+nc -> 250 Recibido
+
+nc <- QUIT
+nc -> 221 Chauchas
+
+mda wait 0
+
diff --git a/cmd/mda-lmtp/test_utf8.cmy b/cmd/mda-lmtp/test_utf8.cmy
new file mode 100644
index 0000000..49dd924
--- /dev/null
+++ b/cmd/mda-lmtp/test_utf8.cmy
@@ -0,0 +1,33 @@
+
+nc unix_listen .test-sock
+
+mda |= ./mda-lmtp --addr=.test-sock --addr_network=unix \
+        -f fröm -d þo < test-email
+
+nc -> 220 Hola desde expect
+
+nc <~ LHLO .*
+nc -> 250-Bienvenido!
+nc -> 250 Contame...
+
+nc <- MAIL FROM:<fröm>
+nc -> 250 Aja
+
+nc <- RCPT TO:<þo>
+nc -> 250 Aja
+
+nc <- DATA
+nc -> 354 Dale
+
+nc <- Subject: test
+nc <-
+nc <- This is a test.
+nc <- .
+
+nc -> 250 Recibido
+
+nc <- QUIT
+nc -> 221 Chauchas
+
+mda wait 0
+