A reflector that has moved to 3.0 will not accept a station that always announces 2.0, and a 2.x reflector still needs one explicit plaintext session. Co-authored-by: Cursor <cursoragent@cursor.com>
141 lines
4.0 KiB
Go
141 lines
4.0 KiB
Go
package station_test
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.neitzel.de/konrad/funknetz/station"
|
|
)
|
|
|
|
func TestVersionErrorFallsBackWhenTheMaximumIs2(t *testing.T) {
|
|
for _, msg := range []string{
|
|
"Unsupported protocol version 3.0. May be at most 2.0.",
|
|
"Unsupported protocol version 3.0. May be at most 2.5.",
|
|
} {
|
|
t.Run(msg, func(t *testing.T) {
|
|
refl := newReflector(t)
|
|
path := writeConfigFile(t, configJSON(t, "127.0.0.1", refl.port, "DL1ABC", "key", 20))
|
|
clock := newFakeClock()
|
|
st, err := station.New(station.Options{ConfigPath: path, Clock: clock})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx, cancel := context.WithCancel(t.Context())
|
|
defer cancel()
|
|
go func() { _ = st.Run(ctx) }()
|
|
refl.accept(t)
|
|
typ, body := refl.readFrame(t)
|
|
if typ != 5 || !versionIs(body, 3, 0) {
|
|
t.Fatalf("type %d body %v", typ, body)
|
|
}
|
|
refl.writeFrame(t, 13, appendStr(nil, msg))
|
|
refl.accept(t)
|
|
typ, body = refl.readFrame(t)
|
|
if typ != 5 || !versionIs(body, 2, 0) {
|
|
t.Fatalf("fallback type %d body %v", typ, body)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVersionErrorBelow2Stops(t *testing.T) {
|
|
for _, msg := range []string{
|
|
"Unsupported protocol version 3.0. May be at most 1.9.",
|
|
"Unsupported protocol version 3.0. May be at most 0.6.",
|
|
} {
|
|
t.Run(msg, func(t *testing.T) {
|
|
refl := newReflector(t)
|
|
path := writeConfigFile(t, configJSON(t, "127.0.0.1", refl.port, "DL1ABC", "key", 20))
|
|
clock := newFakeClock()
|
|
st, err := station.New(station.Options{ConfigPath: path, Clock: clock})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx, cancel := context.WithCancel(t.Context())
|
|
defer cancel()
|
|
go func() { _ = st.Run(ctx) }()
|
|
refl.accept(t)
|
|
refl.readFrame(t)
|
|
refl.writeFrame(t, 13, appendStr(nil, msg))
|
|
got, err := st.Wait(ctx, func(s station.State) bool { return s.Detail == msg })
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.Connection != "Disconnected" || got.Protocol != "" {
|
|
t.Fatalf("State = %+v", got)
|
|
}
|
|
clock.Advance(2 * time.Second)
|
|
refl.ln.(*net.TCPListener).SetDeadline(time.Now().Add(150 * time.Millisecond))
|
|
if conn, err := refl.ln.Accept(); err == nil {
|
|
conn.Close()
|
|
t.Fatal("retried")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDowngradeOtherThan2Stops(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
major, minor uint16
|
|
want string
|
|
}{
|
|
{1, 0, "Unsupported protocol version 1.0"},
|
|
{4, 2, "Unsupported protocol version 4.2"},
|
|
} {
|
|
t.Run(tc.want, func(t *testing.T) {
|
|
refl := newReflector(t)
|
|
path := writeConfigFile(t, configJSON(t, "127.0.0.1", refl.port, "DL1ABC", "key", 20))
|
|
clock := newFakeClock()
|
|
st, err := station.New(station.Options{ConfigPath: path, Clock: clock})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx, cancel := context.WithCancel(t.Context())
|
|
defer cancel()
|
|
go func() { _ = st.Run(ctx) }()
|
|
refl.accept(t)
|
|
refl.readFrame(t)
|
|
refl.writeFrame(t, 6, versionWire(tc.major, tc.minor))
|
|
got, err := st.Wait(ctx, func(s station.State) bool { return s.Detail == tc.want })
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.Protocol != "" || got.Connection != "Disconnected" {
|
|
t.Fatalf("State = %+v", got)
|
|
}
|
|
clock.Advance(2 * time.Second)
|
|
refl.ln.(*net.TCPListener).SetDeadline(time.Now().Add(150 * time.Millisecond))
|
|
if conn, err := refl.ln.Accept(); err == nil {
|
|
conn.Close()
|
|
t.Fatal("retried")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDowngradeDoesNotCreateTheCertificateDirectory(t *testing.T) {
|
|
refl := newReflector(t)
|
|
dir := t.TempDir()
|
|
path := dir + "/funknetz.json"
|
|
body := configWithDir(t, "127.0.0.1", refl.port, "DL1ABC", "key", 20, "./funknetz", "")
|
|
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
clock := newFakeClock()
|
|
st, err := station.New(station.Options{ConfigPath: path, Clock: clock})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx, cancel := context.WithCancel(t.Context())
|
|
defer cancel()
|
|
go func() { _ = st.Run(ctx) }()
|
|
refl.accept(t)
|
|
declineTo2(t, refl)
|
|
if _, err := os.Stat(dir + "/funknetz"); err == nil {
|
|
t.Fatal("created the certificate directory on a 2.0 fallback")
|
|
}
|
|
}
|