Speak protocol 3.0 and fall back to 2.0 only when that is the reflector's maximum.
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>
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user