mirror of
https://github.com/decke/smtprelay.git
synced 2026-11-06 07:51:36 -06:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25c3446610 | ||
|
|
d8eb98b333 | ||
|
|
7b8e4bf844 | ||
|
|
3dbd9d1265 | ||
|
|
5f64de75f6 | ||
|
|
f8b8ed4700 | ||
|
|
5c5ffd5a52 | ||
|
|
a7051eb403 | ||
|
|
7881935f54 | ||
|
|
37279f241c | ||
|
|
85d207c324 | ||
|
|
d064de652b | ||
|
|
043491c180 | ||
|
|
0df87cab3b | ||
|
|
8074b81b6d | ||
|
|
87d3faf18c | ||
|
|
0d43e4c43b | ||
|
|
0eeda67eb0 | ||
|
|
383f02e909 | ||
|
|
ec4adf1ccd | ||
|
|
0408cb87ec | ||
|
|
ad5a5b6d70 | ||
|
|
60285a9bdf | ||
|
|
0dfc26aac7 | ||
|
|
af9668664c | ||
|
|
d0e21b5336 | ||
|
|
651e4fc3d3 | ||
|
|
16eae6d3b4 | ||
|
|
a23724316d | ||
|
|
4a7cbb99b0 |
No files matched your search
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -72,4 +72,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
|
||||
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -76,6 +76,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
||||
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -1,22 +1,22 @@
|
||||
module github.com/decke/smtprelay
|
||||
|
||||
require (
|
||||
github.com/DeRuina/timberjack v1.4.6
|
||||
github.com/chrj/smtpd v1.0.0
|
||||
github.com/DeRuina/timberjack v1.4.8
|
||||
github.com/chrj/smtpd v1.0.1
|
||||
github.com/fsnotify/fsnotify v1.10.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/peterbourgon/ff/v3 v3.4.0
|
||||
github.com/rs/zerolog v1.35.1
|
||||
github.com/stretchr/testify v1.12.1
|
||||
golang.org/x/crypto v0.55.0
|
||||
golang.org/x/crypto v0.58.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/klauspost/compress v1.18.6 // indirect
|
||||
github.com/klauspost/compress v1.18.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/sys v0.49.0 // indirect
|
||||
)
|
||||
|
||||
go 1.25.0
|
||||
go 1.26.0
|
||||
@@ -1,15 +1,15 @@
|
||||
github.com/DeRuina/timberjack v1.4.6 h1:ixA4vWcXt160M69ZbhUTLfSOOlEtEE+7hHEgDWIXUiI=
|
||||
github.com/DeRuina/timberjack v1.4.6/go.mod h1:RLoeQrwrCGIEF8gO5nV5b/gMD0QIy7bzQhBUgpp1EqE=
|
||||
github.com/chrj/smtpd v1.0.0 h1:jChSfLzAhrSxTky0EZ6oW+UKiqdnepdknWYRkPeA+ZE=
|
||||
github.com/chrj/smtpd v1.0.0/go.mod h1:zEP61gNDlWp/jdUqBcq/ykIbgOERyRvwfMsRLl3h9gM=
|
||||
github.com/DeRuina/timberjack v1.4.8 h1:V7SIoCzkyWD93WmyKECSX+tMu/hLqQQvptlhEsbBIhI=
|
||||
github.com/DeRuina/timberjack v1.4.8/go.mod h1:DCXjOescYyzTrOryf57SEbSeCOqkBQ3QjH7Pn03i5Cs=
|
||||
github.com/chrj/smtpd v1.0.1 h1:HmC5/iGdI27q4JJn58uaANAOUE+QC7ZYZnDlQWJEph4=
|
||||
github.com/chrj/smtpd v1.0.1/go.mod h1:zEP61gNDlWp/jdUqBcq/ykIbgOERyRvwfMsRLl3h9gM=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
|
||||
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/klauspost/compress v1.18.7 h1:aUyZsS4kH3QTKurYhAOwAHxllVPnOthb3vPfnF1Ehjw=
|
||||
github.com/klauspost/compress v1.18.7/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
|
||||
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||
@@ -22,7 +22,7 @@ github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWD
|
||||
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
|
||||
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
|
||||
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
||||
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
|
||||
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54=
|
||||
golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w=
|
||||
golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA=
|
||||
golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
+2
-1
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"net/url"
|
||||
)
|
||||
@@ -55,7 +56,7 @@ func ParseRemote(remoteURL string) (*Remote, error) {
|
||||
Scheme: u.Scheme,
|
||||
Hostname: hostname,
|
||||
Port: port,
|
||||
Addr: fmt.Sprintf("%s:%s", hostname, port),
|
||||
Addr: net.JoinHostPort(hostname, port),
|
||||
}
|
||||
|
||||
if u.User != nil {
|
||||
|
||||
@@ -107,6 +107,26 @@ func TestValidRemoteUrls(t *testing.T) {
|
||||
}, "starttls://user:pass@email.com:8425/sender@website.com?auth=login&skipVerify")
|
||||
}
|
||||
|
||||
func TestIPv6RemoteUrls(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
url, scheme, port string
|
||||
}{
|
||||
{"smtp://[::1]", "smtp", "25"},
|
||||
{"smtps://[::1]", "smtps", "465"},
|
||||
{"starttls://[::1]", "starttls", "587"},
|
||||
{"smtp://[::1]:2525", "smtp", "2525"},
|
||||
} {
|
||||
t.Run(test.url, func(t *testing.T) {
|
||||
AssertRemoteUrlEquals(t, &Remote{
|
||||
Scheme: test.scheme,
|
||||
Hostname: "::1",
|
||||
Port: test.port,
|
||||
Addr: "[::1]:" + test.port,
|
||||
}, test.url)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMissingScheme(t *testing.T) {
|
||||
_, err := ParseRemote("http://user:pass@email.com:8425/sender@website.com")
|
||||
assert.NotNil(t, err, "Err must be present")
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/textproto"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSendMailIPv6Remote(t *testing.T) {
|
||||
listener, err := net.Listen("tcp6", "[::1]:0")
|
||||
if err != nil {
|
||||
t.Skipf("IPv6 loopback unavailable: %v", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
if err := listener.(*net.TCPListener).SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
result := make(chan error, 1)
|
||||
go func() {
|
||||
result <- serveTestSMTP(listener)
|
||||
}()
|
||||
|
||||
remote, err := ParseRemote("smtp://" + listener.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := SendMail(remote, "sender@example.invalid", []string{"recipient@example.invalid"}, []byte("Subject: loopback test\r\n\r\nsynthetic fixture\r\n")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := <-result; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// This sink accepts only the synthetic transaction used above, never relaying it.
|
||||
func serveTestSMTP(listener net.Listener) error {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
||||
return err
|
||||
}
|
||||
text := textproto.NewConn(conn)
|
||||
if err := text.PrintfLine("220 loopback test"); err != nil {
|
||||
return err
|
||||
}
|
||||
commands := []struct{ command, response string }{
|
||||
{"EHLO " + *hostName, "250 loopback test"},
|
||||
{"MAIL FROM:<sender@example.invalid>", "250 OK"},
|
||||
{"RCPT TO:<recipient@example.invalid>", "250 OK"},
|
||||
{"DATA", "354 End with a dot"},
|
||||
}
|
||||
for _, step := range commands {
|
||||
line, err := text.ReadLine()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if line != step.command {
|
||||
return fmt.Errorf("command = %q, want %q", line, step.command)
|
||||
}
|
||||
if err := text.PrintfLine("%s", step.response); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
data, err := text.ReadDotBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if string(data) != "Subject: loopback test\n\nsynthetic fixture\n" {
|
||||
return fmt.Errorf("unexpected DATA: %q", data)
|
||||
}
|
||||
if err := text.PrintfLine("250 OK"); err != nil {
|
||||
return err
|
||||
}
|
||||
line, err := text.ReadLine()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if line != "QUIT" {
|
||||
return fmt.Errorf("command = %q, want QUIT", line)
|
||||
}
|
||||
return text.PrintfLine("221 Bye")
|
||||
}
|
||||
Reference in new issue
Block a user