Skip to content

Commit

Permalink
move config to a private data structure
Browse files Browse the repository at this point in the history
  • Loading branch information
jyyi1 committed Aug 17, 2023
1 parent e011453 commit bff3827
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 78 deletions.
22 changes: 11 additions & 11 deletions outline/config/config.go → outline/device/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package config
package device

import (
"encoding/json"
"fmt"
"net"
"strconv"

"github.com/Jigsaw-Code/outline-sdk/transport/shadowsocks"
)

// An internal configuration data structure to be used by Outline transports.
type TransportConfig struct {
Hostname string
Port int
CryptoKey *shadowsocks.EncryptionKey
Prefix []byte
type transportConfig struct {
RemoteAddress string // the remote server address of "host:port"
CryptoKey *shadowsocks.EncryptionKey
Prefix []byte
}

// The configuration interface between the Outline backend and Outline apps.
Expand All @@ -39,9 +40,9 @@ type configJSON struct {
Prefix string `json:"prefix"`
}

// ParseConfigFromJSON parses a transport configuration string in JSON format, and returns a corresponding
// parseConfigFromJSON parses a transport configuration string in JSON format, and returns a corresponding
// TransportConfig. The JSON string `in` must match the ShadowsocksSessionConfig interface defined in Outline Client.
func ParseConfigFromJSON(in string) (config *TransportConfig, err error) {
func parseConfigFromJSON(in string) (config *transportConfig, err error) {
var confJson configJSON
if err = json.Unmarshal([]byte(in), &confJson); err != nil {
return nil, err
Expand All @@ -50,9 +51,8 @@ func ParseConfigFromJSON(in string) (config *TransportConfig, err error) {
return nil, fmt.Errorf("invalid configuration: %w", err)
}

config = &TransportConfig{
Hostname: confJson.Host,
Port: int(confJson.Port),
config = &transportConfig{
RemoteAddress: net.JoinHostPort(confJson.Host, strconv.Itoa(int(confJson.Port))),
}
if config.CryptoKey, err = shadowsocks.NewEncryptionKey(confJson.Method, confJson.Password); err != nil {
return nil, fmt.Errorf("invalid cipher: %w", err)
Expand Down
66 changes: 29 additions & 37 deletions outline/config/config_test.go → outline/device/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package config
package device

import (
"testing"
Expand All @@ -22,45 +22,39 @@ import (

func Test_ParseConfigFromJSON(t *testing.T) {
tests := []struct {
name string
input string
expectErr bool
expectHost string
expectPort int
expectPrefix []byte
name string
input string
expectErr bool
expectAddress string
expectPrefix []byte
}{
{
name: "normal config",
input: `{"host":"192.0.2.1","port":12345,"method":"chacha20-ietf-poly1305","password":"abcd1234"}`,
expectHost: "192.0.2.1",
expectPort: 12345,
name: "normal config",
input: `{"host":"192.0.2.1","port":12345,"method":"chacha20-ietf-poly1305","password":"abcd1234"}`,
expectAddress: "192.0.2.1:12345",
},
{
name: "normal config with prefix",
input: `{"host":"192.0.2.1","port":12345,"method":"aes-128-gcm","password":"abcd1234","prefix":"abc 123"}`,
expectHost: "192.0.2.1",
expectPort: 12345,
expectPrefix: []byte("abc 123"),
name: "normal config with prefix",
input: `{"host":"192.0.2.1","port":12345,"method":"aes-128-gcm","password":"abcd1234","prefix":"abc 123"}`,
expectAddress: "192.0.2.1:12345",
expectPrefix: []byte("abc 123"),
},
{
name: "normal config with extra fields",
input: `{"extra_field":"ignored","host":"192.0.2.1","port":12345,"method":"aes-192-gcm","password":"abcd1234"}`,
expectHost: "192.0.2.1",
expectPort: 12345,
name: "normal config with extra fields",
input: `{"extra_field":"ignored","host":"192.0.2.1","port":12345,"method":"aes-192-gcm","password":"abcd1234"}`,
expectAddress: "192.0.2.1:12345",
},
{
name: "unprintable prefix",
input: `{"host":"192.0.2.1","port":12345,"method":"AES-256-gcm","password":"abcd1234","prefix":"abc 123","prefix":"\u0000\u0080\u00ff"}`,
expectHost: "192.0.2.1",
expectPort: 12345,
expectPrefix: []byte{0x00, 0x80, 0xff},
name: "unprintable prefix",
input: `{"host":"192.0.2.1","port":12345,"method":"AES-256-gcm","password":"abcd1234","prefix":"abc 123","prefix":"\u0000\u0080\u00ff"}`,
expectAddress: "192.0.2.1:12345",
expectPrefix: []byte{0x00, 0x80, 0xff},
},
{
name: "multi-byte utf-8 prefix",
input: `{"host":"192.0.2.1","port":12345,"method":"chacha20-ietf-poly1305","password":"abcd1234","prefix":"abc 123","prefix":"` + "\xc2\x80\xc2\x81\xc3\xbd\xc3\xbf" + `"}`,
expectHost: "192.0.2.1",
expectPort: 12345,
expectPrefix: []byte{0x80, 0x81, 0xfd, 0xff},
name: "multi-byte utf-8 prefix",
input: `{"host":"192.0.2.1","port":12345,"method":"chacha20-ietf-poly1305","password":"abcd1234","prefix":"abc 123","prefix":"` + "\xc2\x80\xc2\x81\xc3\xbd\xc3\xbf" + `"}`,
expectAddress: "192.0.2.1:12345",
expectPrefix: []byte{0x80, 0x81, 0xfd, 0xff},
},
{
name: "missing host",
Expand All @@ -73,10 +67,9 @@ func Test_ParseConfigFromJSON(t *testing.T) {
expectErr: true,
},
{
name: "missing method",
input: `{"host":"192.0.2.1","port":12345,"password":"abcd1234"}`,
expectHost: "192.0.2.1",
expectErr: true,
name: "missing method",
input: `{"host":"192.0.2.1","port":12345,"password":"abcd1234"}`,
expectErr: true,
},
{
name: "missing password",
Expand Down Expand Up @@ -126,13 +119,12 @@ func Test_ParseConfigFromJSON(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseConfigFromJSON(tt.input)
got, err := parseConfigFromJSON(tt.input)
if tt.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.expectHost, got.Hostname)
require.Equal(t, tt.expectPort, got.Port)
require.Equal(t, tt.expectAddress, got.RemoteAddress)
require.NotNil(t, got.CryptoKey)
require.Equal(t, tt.expectPrefix, got.Prefix)
}
Expand Down
3 changes: 1 addition & 2 deletions outline/device/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package device
import (
"fmt"

"github.com/Jigsaw-Code/outline-apps/outline/config"
"github.com/Jigsaw-Code/outline-sdk/network"
"github.com/Jigsaw-Code/outline-sdk/network/lwip2transport"
"github.com/Jigsaw-Code/outline-sdk/transport"
Expand All @@ -37,7 +36,7 @@ type OutlineDevice struct {

// NewOutlineDevice creates a new [OutlineDevice] that can relay traffic to a remote Outline server.
func NewOutlineDevice(configJSON string) (d *OutlineDevice, err error) {
config, err := config.ParseConfigFromJSON(configJSON)
config, err := parseConfigFromJSON(configJSON)
if err != nil {
return nil, err
}
Expand Down
25 changes: 25 additions & 0 deletions outline/device/packet_listener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2023 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package device

import (
"github.com/Jigsaw-Code/outline-sdk/transport"
"github.com/Jigsaw-Code/outline-sdk/transport/shadowsocks"
)

// newOutlinePacketListener creates a [transport.PacketListener] that connects to the remote proxy using `config`.
func newOutlinePacketListener(config *transportConfig) (transport.PacketListener, error) {
return shadowsocks.NewPacketListener(&transport.UDPEndpoint{Address: config.RemoteAddress}, config.CryptoKey)
}
27 changes: 6 additions & 21 deletions outline/device/packet_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,10 @@ package device
import (
"context"
"fmt"
"net"
"strconv"

"github.com/Jigsaw-Code/outline-apps/outline/config"
"github.com/Jigsaw-Code/outline-sdk/network"
"github.com/Jigsaw-Code/outline-sdk/network/dnstruncate"
"github.com/Jigsaw-Code/outline-sdk/transport"
"github.com/Jigsaw-Code/outline-sdk/transport/shadowsocks"
"github.com/Jigsaw-Code/outline-sdk/x/connectivity"
)

Expand All @@ -34,10 +30,14 @@ type outlinePacketProxy struct {
remotePktListener transport.PacketListener // this will be used in connectivity test
}

func newOutlinePacketProxy(config *config.TransportConfig) (proxy *outlinePacketProxy, err error) {
func newOutlinePacketProxy(config *transportConfig) (proxy *outlinePacketProxy, err error) {
proxy = &outlinePacketProxy{}

if proxy.remotePktListener, proxy.remote, err = makeRemotePacketProxy(config); err != nil {
if proxy.remotePktListener, err = newOutlinePacketListener(config); err != nil {
return nil, fmt.Errorf("failed to create packet listener: %w", err)
}

if proxy.remote, err = network.NewPacketProxyFromPacketListener(proxy.remotePktListener); err != nil {
return nil, fmt.Errorf("failed to create packet proxy: %w", err)
}

Expand All @@ -52,21 +52,6 @@ func newOutlinePacketProxy(config *config.TransportConfig) (proxy *outlinePacket
return
}

// makeRemotePacketProxy creates a pair of [transport.PacketListener] and [network.PacketProxy] that connects to the
// remote proxy using `config`.
func makeRemotePacketProxy(
config *config.TransportConfig,
) (pl transport.PacketListener, pp network.PacketProxy, err error) {
server := net.JoinHostPort(config.Hostname, strconv.Itoa(config.Port))
if pl, err = shadowsocks.NewPacketListener(&transport.UDPEndpoint{Address: server}, config.CryptoKey); err != nil {
return nil, nil, err
}
if pp, err = network.NewPacketProxyFromPacketListener(pl); err != nil {
return nil, nil, err
}
return
}

// testConnectivityAndRefresh tests whether the remote server can handle packet traffic and sets the underlying proxy
// to be either remote or fallback according to the result.
func (proxy *outlinePacketProxy) testConnectivityAndRefresh(resolver, domain string) error {
Expand Down
9 changes: 2 additions & 7 deletions outline/device/stream_dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,13 @@
package device

import (
"net"
"strconv"

"github.com/Jigsaw-Code/outline-apps/outline/config"
"github.com/Jigsaw-Code/outline-sdk/transport"
"github.com/Jigsaw-Code/outline-sdk/transport/shadowsocks"
)

// newOutlineStreamDialer creates a [transport.StreamDialer] that connects to the remote proxy using `config`.
func newOutlineStreamDialer(config *config.TransportConfig) (transport.StreamDialer, error) {
server := net.JoinHostPort(config.Hostname, strconv.Itoa(config.Port))
dialer, err := shadowsocks.NewStreamDialer(&transport.TCPEndpoint{Address: server}, config.CryptoKey)
func newOutlineStreamDialer(config *transportConfig) (transport.StreamDialer, error) {
dialer, err := shadowsocks.NewStreamDialer(&transport.TCPEndpoint{Address: config.RemoteAddress}, config.CryptoKey)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit bff3827

Please sign in to comment.