From 07f8db9dc27c3a30122c0957f7d960ed20d139f8 Mon Sep 17 00:00:00 2001 From: Dionysis Grigoropoulos Date: Tue, 8 Mar 2022 13:25:33 +0200 Subject: [PATCH] feat: add support for OpenBSD (#703) Closes https://github.com/ooni/probe/issues/2052 --- internal/netxlite/errno_openbsd.go | 112 ++++++++++++ internal/netxlite/errno_openbsd_test.go | 188 ++++++++++++++++++++ internal/netxlite/internal/generrno/main.go | 3 +- internal/platform/platform.go | 6 +- internal/platform/platform_test.go | 5 +- 5 files changed, 310 insertions(+), 4 deletions(-) create mode 100644 internal/netxlite/errno_openbsd.go create mode 100644 internal/netxlite/errno_openbsd_test.go diff --git a/internal/netxlite/errno_openbsd.go b/internal/netxlite/errno_openbsd.go new file mode 100644 index 0000000..60cddba --- /dev/null +++ b/internal/netxlite/errno_openbsd.go @@ -0,0 +1,112 @@ +// Code generated by go generate; DO NOT EDIT. +// Generated: 2022-03-05 00:39:22.759235545 +0200 EET m=+5.562977793 + +package netxlite + +import ( + "errors" + "syscall" + + "golang.org/x/sys/unix" +) + +// This enumeration provides a canonical name for +// every system-call error we support. Note: this list +// is system dependent. You're currently looking at +// the list of errors for openbsd. +const ( + ECONNREFUSED = unix.ECONNREFUSED + ECONNRESET = unix.ECONNRESET + EHOSTUNREACH = unix.EHOSTUNREACH + ETIMEDOUT = unix.ETIMEDOUT + EAFNOSUPPORT = unix.EAFNOSUPPORT + EADDRINUSE = unix.EADDRINUSE + EADDRNOTAVAIL = unix.EADDRNOTAVAIL + EISCONN = unix.EISCONN + EFAULT = unix.EFAULT + EBADF = unix.EBADF + ECONNABORTED = unix.ECONNABORTED + EALREADY = unix.EALREADY + EDESTADDRREQ = unix.EDESTADDRREQ + EINTR = unix.EINTR + EINVAL = unix.EINVAL + EMSGSIZE = unix.EMSGSIZE + ENETDOWN = unix.ENETDOWN + ENETRESET = unix.ENETRESET + ENETUNREACH = unix.ENETUNREACH + ENOBUFS = unix.ENOBUFS + ENOPROTOOPT = unix.ENOPROTOOPT + ENOTSOCK = unix.ENOTSOCK + ENOTCONN = unix.ENOTCONN + EWOULDBLOCK = unix.EWOULDBLOCK + EACCES = unix.EACCES + EPROTONOSUPPORT = unix.EPROTONOSUPPORT + EPROTOTYPE = unix.EPROTOTYPE +) + +// classifySyscallError converts a syscall error to the +// proper OONI error. Returns the OONI error string +// on success, an empty string otherwise. +func classifySyscallError(err error) string { + var errno syscall.Errno + if !errors.As(err, &errno) { + return "" + } + switch errno { + case unix.ECONNREFUSED: + return FailureConnectionRefused + case unix.ECONNRESET: + return FailureConnectionReset + case unix.EHOSTUNREACH: + return FailureHostUnreachable + case unix.ETIMEDOUT: + return FailureTimedOut + case unix.EAFNOSUPPORT: + return FailureAddressFamilyNotSupported + case unix.EADDRINUSE: + return FailureAddressInUse + case unix.EADDRNOTAVAIL: + return FailureAddressNotAvailable + case unix.EISCONN: + return FailureAlreadyConnected + case unix.EFAULT: + return FailureBadAddress + case unix.EBADF: + return FailureBadFileDescriptor + case unix.ECONNABORTED: + return FailureConnectionAborted + case unix.EALREADY: + return FailureConnectionAlreadyInProgress + case unix.EDESTADDRREQ: + return FailureDestinationAddressRequired + case unix.EINTR: + return FailureInterrupted + case unix.EINVAL: + return FailureInvalidArgument + case unix.EMSGSIZE: + return FailureMessageSize + case unix.ENETDOWN: + return FailureNetworkDown + case unix.ENETRESET: + return FailureNetworkReset + case unix.ENETUNREACH: + return FailureNetworkUnreachable + case unix.ENOBUFS: + return FailureNoBufferSpace + case unix.ENOPROTOOPT: + return FailureNoProtocolOption + case unix.ENOTSOCK: + return FailureNotASocket + case unix.ENOTCONN: + return FailureNotConnected + case unix.EWOULDBLOCK: + return FailureOperationWouldBlock + case unix.EACCES: + return FailurePermissionDenied + case unix.EPROTONOSUPPORT: + return FailureProtocolNotSupported + case unix.EPROTOTYPE: + return FailureWrongProtocolType + } + return "" +} diff --git a/internal/netxlite/errno_openbsd_test.go b/internal/netxlite/errno_openbsd_test.go new file mode 100644 index 0000000..2c7dc03 --- /dev/null +++ b/internal/netxlite/errno_openbsd_test.go @@ -0,0 +1,188 @@ +// Code generated by go generate; DO NOT EDIT. +// Generated: 2022-03-05 00:39:24.329954472 +0200 EET m=+7.133696441 + +package netxlite + +import ( + "io" + "syscall" + "testing" + + "golang.org/x/sys/unix" +) + +func TestClassifySyscallError(t *testing.T) { + t.Run("for a non-syscall error", func(t *testing.T) { + if v := classifySyscallError(io.EOF); v != "" { + t.Fatalf("expected empty string, got '%s'", v) + } + }) + + t.Run("for ECONNREFUSED", func(t *testing.T) { + if v := classifySyscallError(unix.ECONNREFUSED); v != FailureConnectionRefused { + t.Fatalf("expected '%s', got '%s'", FailureConnectionRefused, v) + } + }) + + t.Run("for ECONNRESET", func(t *testing.T) { + if v := classifySyscallError(unix.ECONNRESET); v != FailureConnectionReset { + t.Fatalf("expected '%s', got '%s'", FailureConnectionReset, v) + } + }) + + t.Run("for EHOSTUNREACH", func(t *testing.T) { + if v := classifySyscallError(unix.EHOSTUNREACH); v != FailureHostUnreachable { + t.Fatalf("expected '%s', got '%s'", FailureHostUnreachable, v) + } + }) + + t.Run("for ETIMEDOUT", func(t *testing.T) { + if v := classifySyscallError(unix.ETIMEDOUT); v != FailureTimedOut { + t.Fatalf("expected '%s', got '%s'", FailureTimedOut, v) + } + }) + + t.Run("for EAFNOSUPPORT", func(t *testing.T) { + if v := classifySyscallError(unix.EAFNOSUPPORT); v != FailureAddressFamilyNotSupported { + t.Fatalf("expected '%s', got '%s'", FailureAddressFamilyNotSupported, v) + } + }) + + t.Run("for EADDRINUSE", func(t *testing.T) { + if v := classifySyscallError(unix.EADDRINUSE); v != FailureAddressInUse { + t.Fatalf("expected '%s', got '%s'", FailureAddressInUse, v) + } + }) + + t.Run("for EADDRNOTAVAIL", func(t *testing.T) { + if v := classifySyscallError(unix.EADDRNOTAVAIL); v != FailureAddressNotAvailable { + t.Fatalf("expected '%s', got '%s'", FailureAddressNotAvailable, v) + } + }) + + t.Run("for EISCONN", func(t *testing.T) { + if v := classifySyscallError(unix.EISCONN); v != FailureAlreadyConnected { + t.Fatalf("expected '%s', got '%s'", FailureAlreadyConnected, v) + } + }) + + t.Run("for EFAULT", func(t *testing.T) { + if v := classifySyscallError(unix.EFAULT); v != FailureBadAddress { + t.Fatalf("expected '%s', got '%s'", FailureBadAddress, v) + } + }) + + t.Run("for EBADF", func(t *testing.T) { + if v := classifySyscallError(unix.EBADF); v != FailureBadFileDescriptor { + t.Fatalf("expected '%s', got '%s'", FailureBadFileDescriptor, v) + } + }) + + t.Run("for ECONNABORTED", func(t *testing.T) { + if v := classifySyscallError(unix.ECONNABORTED); v != FailureConnectionAborted { + t.Fatalf("expected '%s', got '%s'", FailureConnectionAborted, v) + } + }) + + t.Run("for EALREADY", func(t *testing.T) { + if v := classifySyscallError(unix.EALREADY); v != FailureConnectionAlreadyInProgress { + t.Fatalf("expected '%s', got '%s'", FailureConnectionAlreadyInProgress, v) + } + }) + + t.Run("for EDESTADDRREQ", func(t *testing.T) { + if v := classifySyscallError(unix.EDESTADDRREQ); v != FailureDestinationAddressRequired { + t.Fatalf("expected '%s', got '%s'", FailureDestinationAddressRequired, v) + } + }) + + t.Run("for EINTR", func(t *testing.T) { + if v := classifySyscallError(unix.EINTR); v != FailureInterrupted { + t.Fatalf("expected '%s', got '%s'", FailureInterrupted, v) + } + }) + + t.Run("for EINVAL", func(t *testing.T) { + if v := classifySyscallError(unix.EINVAL); v != FailureInvalidArgument { + t.Fatalf("expected '%s', got '%s'", FailureInvalidArgument, v) + } + }) + + t.Run("for EMSGSIZE", func(t *testing.T) { + if v := classifySyscallError(unix.EMSGSIZE); v != FailureMessageSize { + t.Fatalf("expected '%s', got '%s'", FailureMessageSize, v) + } + }) + + t.Run("for ENETDOWN", func(t *testing.T) { + if v := classifySyscallError(unix.ENETDOWN); v != FailureNetworkDown { + t.Fatalf("expected '%s', got '%s'", FailureNetworkDown, v) + } + }) + + t.Run("for ENETRESET", func(t *testing.T) { + if v := classifySyscallError(unix.ENETRESET); v != FailureNetworkReset { + t.Fatalf("expected '%s', got '%s'", FailureNetworkReset, v) + } + }) + + t.Run("for ENETUNREACH", func(t *testing.T) { + if v := classifySyscallError(unix.ENETUNREACH); v != FailureNetworkUnreachable { + t.Fatalf("expected '%s', got '%s'", FailureNetworkUnreachable, v) + } + }) + + t.Run("for ENOBUFS", func(t *testing.T) { + if v := classifySyscallError(unix.ENOBUFS); v != FailureNoBufferSpace { + t.Fatalf("expected '%s', got '%s'", FailureNoBufferSpace, v) + } + }) + + t.Run("for ENOPROTOOPT", func(t *testing.T) { + if v := classifySyscallError(unix.ENOPROTOOPT); v != FailureNoProtocolOption { + t.Fatalf("expected '%s', got '%s'", FailureNoProtocolOption, v) + } + }) + + t.Run("for ENOTSOCK", func(t *testing.T) { + if v := classifySyscallError(unix.ENOTSOCK); v != FailureNotASocket { + t.Fatalf("expected '%s', got '%s'", FailureNotASocket, v) + } + }) + + t.Run("for ENOTCONN", func(t *testing.T) { + if v := classifySyscallError(unix.ENOTCONN); v != FailureNotConnected { + t.Fatalf("expected '%s', got '%s'", FailureNotConnected, v) + } + }) + + t.Run("for EWOULDBLOCK", func(t *testing.T) { + if v := classifySyscallError(unix.EWOULDBLOCK); v != FailureOperationWouldBlock { + t.Fatalf("expected '%s', got '%s'", FailureOperationWouldBlock, v) + } + }) + + t.Run("for EACCES", func(t *testing.T) { + if v := classifySyscallError(unix.EACCES); v != FailurePermissionDenied { + t.Fatalf("expected '%s', got '%s'", FailurePermissionDenied, v) + } + }) + + t.Run("for EPROTONOSUPPORT", func(t *testing.T) { + if v := classifySyscallError(unix.EPROTONOSUPPORT); v != FailureProtocolNotSupported { + t.Fatalf("expected '%s', got '%s'", FailureProtocolNotSupported, v) + } + }) + + t.Run("for EPROTOTYPE", func(t *testing.T) { + if v := classifySyscallError(unix.EPROTOTYPE); v != FailureWrongProtocolType { + t.Fatalf("expected '%s', got '%s'", FailureWrongProtocolType, v) + } + }) + + t.Run("for the zero errno value", func(t *testing.T) { + if v := classifySyscallError(syscall.Errno(0)); v != "" { + t.Fatalf("expected empty string, got '%s'", v) + } + }) +} diff --git a/internal/netxlite/internal/generrno/main.go b/internal/netxlite/internal/generrno/main.go index ec76d8b..6a878ce 100644 --- a/internal/netxlite/internal/generrno/main.go +++ b/internal/netxlite/internal/generrno/main.go @@ -173,7 +173,7 @@ var Specs = []*ErrorSpec{ // of the related golang.org/x/sys/$name library. func mapSystemToLibrary(system string) string { switch system { - case "darwin", "freebsd", "linux": + case "darwin", "freebsd", "openbsd", "linux": return "unix" case "windows": return "windows" @@ -364,6 +364,7 @@ func writeSystemSpecificTestFile(system string) { var SupportedSystems = []string{ "darwin", "freebsd", + "openbsd", "linux", "windows", } diff --git a/internal/platform/platform.go b/internal/platform/platform.go index 70519ae..2383301 100644 --- a/internal/platform/platform.go +++ b/internal/platform/platform.go @@ -18,7 +18,9 @@ import "runtime" // // 5. "freebsd" // -// 6. "unknown" +// 6. "openbsd" +// +// 7. "unknown" // // You should use this name to annotate measurements. func Name() string { @@ -32,7 +34,7 @@ func name(goos string) string { // // See https://golang.org/doc/go1.16#darwin switch goos { - case "android", "freebsd", "ios", "linux", "windows": + case "android", "freebsd", "openbsd", "ios", "linux", "windows": return goos case "darwin": return "macos" diff --git a/internal/platform/platform_test.go b/internal/platform/platform_test.go index 8772e4e..02f1ff4 100644 --- a/internal/platform/platform_test.go +++ b/internal/platform/platform_test.go @@ -8,7 +8,7 @@ import ( func TestGood(t *testing.T) { var expected bool switch Name() { - case "android", "freebsd", "ios", "linux", "macos", "windows": + case "android", "freebsd", "openbsd", "ios", "linux", "macos", "windows": expected = true } if !expected { @@ -26,6 +26,9 @@ func TestName(t *testing.T) { }, { expected: "freebsd", goos: "freebsd", + }, { + expected: "openbsd", + goos: "openbsd", }, { expected: "ios", goos: "ios",