forked from Jigsaw-Code/outline-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OOB and disOOB implementation #2
Open
siriusfreak
wants to merge
21
commits into
main
Choose a base branch
from
bye-dpi
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
639ff72
OOB and disOOB implementation
siriusfreak 75fb663
OOB and disOOB implementation
siriusfreak a50b014
OOB and disOOB implementation
siriusfreak aaae1e5
OOB and disOOB implementation
siriusfreak a25de7a
OOB and disOOB implementation
siriusfreak 250a731
OOB and disOOB implementation
siriusfreak ffb58dc
OOB and disOOB implementation
siriusfreak 5cd7504
OOB and disOOB implementation
siriusfreak a0e3a8c
OOB and disOOB implementation
siriusfreak b65ad95
OOB and disOOB implementation
siriusfreak 9e0d954
OOB and disOOB implementation
siriusfreak d16f104
OOB and disOOB implementation
siriusfreak 84b696d
OOB and disOOB implementation
siriusfreak 2e298a8
OOB and disOOB implementation
siriusfreak 5a3532d
OOB and disOOB implementation
siriusfreak c8f3af7
OOB and disOOB implementation
siriusfreak 175eda6
OOB and disOOB implementation
siriusfreak 8b9fff0
merge main:
siriusfreak afde648
review fixes
siriusfreak 82bceb5
add test
siriusfreak 5b7b486
add CA
siriusfreak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package configurl | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/Jigsaw-Code/outline-sdk/transport" | ||
"github.com/Jigsaw-Code/outline-sdk/x/oob" | ||
) | ||
|
||
func registerOOBStreamDialer(r TypeRegistry[transport.StreamDialer], typeID string, newSD BuildFunc[transport.StreamDialer]) { | ||
r.RegisterType(typeID, func(ctx context.Context, config *Config) (transport.StreamDialer, error) { | ||
sd, err := newSD(ctx, config.BaseConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
params := config.URL.Opaque | ||
|
||
splitStr := strings.Split(params, ":") | ||
if len(splitStr) != 4 { | ||
return nil, fmt.Errorf("oob: config should be in oob:<number>:<char>:<boolean>:<interval> format") | ||
} | ||
|
||
position, err := strconv.Atoi(splitStr[0]) | ||
if err != nil { | ||
return nil, fmt.Errorf("oob: oob position is not a number: %v", splitStr[0]) | ||
} | ||
|
||
if len(splitStr[1]) != 1 { | ||
return nil, fmt.Errorf("oob: oob byte should be a single character: %v", splitStr[1]) | ||
} | ||
char := splitStr[1][0] | ||
|
||
disOOB, err := strconv.ParseBool(splitStr[2]) | ||
if err != nil { | ||
return nil, fmt.Errorf("oob: disOOB is not a boolean: %v", splitStr[2]) | ||
} | ||
|
||
delay, err := time.ParseDuration(splitStr[3]) | ||
if err != nil { | ||
return nil, fmt.Errorf("oob: delay is not a duration: %v", splitStr[3]) | ||
} | ||
return oob.NewStreamDialer(sd, int64(position), char, disOOB, delay) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package oob | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"net" | ||
"time" | ||
|
||
"github.com/Jigsaw-Code/outline-sdk/transport" | ||
"github.com/Jigsaw-Code/outline-sdk/x/sockopt" | ||
) | ||
|
||
// oobDialer is a dialer that applies the OOB and disOOB strategies. | ||
type oobDialer struct { | ||
dialer transport.StreamDialer | ||
opts sockopt.TCPOptions | ||
oobByte byte | ||
oobPosition int64 | ||
disOOB bool | ||
delay time.Duration | ||
} | ||
|
||
// NewStreamDialer creates a [transport.StreamDialer] that applies OOB byte sending at "oobPosition" and supports disOOB. | ||
// "oobByte" specifies the value of the byte to send out-of-band. | ||
func NewStreamDialer(dialer transport.StreamDialer, | ||
oobPosition int64, oobByte byte, disOOB bool, delay time.Duration) (transport.StreamDialer, error) { | ||
if dialer == nil { | ||
return nil, errors.New("argument dialer must not be nil") | ||
} | ||
return &oobDialer{ | ||
dialer: dialer, | ||
oobPosition: oobPosition, | ||
oobByte: oobByte, | ||
disOOB: disOOB, | ||
delay: delay, | ||
}, nil | ||
} | ||
|
||
// DialStream implements [transport.StreamDialer].DialStream with OOB and disOOB support. | ||
func (d *oobDialer) DialStream(ctx context.Context, remoteAddr string) (transport.StreamConn, error) { | ||
innerConn, err := d.dialer.DialStream(ctx, remoteAddr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// this strategy only works when we set TCP as a strategy | ||
tcpConn, ok := innerConn.(*net.TCPConn) | ||
if !ok { | ||
return nil, fmt.Errorf("oob: only works with direct TCP connections") | ||
} | ||
|
||
opts, err := sockopt.NewTCPOptions(tcpConn) | ||
if err != nil { | ||
return nil, fmt.Errorf("oob: unable to get TCP options: %w", err) | ||
} | ||
|
||
dw := NewWriter(tcpConn, opts, d.oobPosition, d.oobByte, d.disOOB, d.delay) | ||
|
||
return transport.WrapConn(innerConn, innerConn, dw), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package oob | ||
|
||
import ( | ||
"bufio" | ||
"context" | ||
"net" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"github.com/stretchr/testify/suite" | ||
|
||
"github.com/Jigsaw-Code/outline-sdk/transport" | ||
) | ||
|
||
const ( | ||
msg = "Hello OOB!\n" | ||
msgLen = len(msg) | ||
) | ||
|
||
// OOBDialerTestSuite - test suite for testing oobDialer and oobWriter | ||
type OOBDialerTestSuite struct { | ||
suite.Suite | ||
server net.Listener | ||
dataChan chan []byte | ||
serverAddr string | ||
} | ||
|
||
// SetupSuite - runs once before all tests | ||
func (suite *OOBDialerTestSuite) SetupSuite() { | ||
// Start TCP server | ||
listener, dataChan := startTestServer(suite.T()) | ||
suite.server = listener | ||
suite.dataChan = dataChan | ||
suite.serverAddr = listener.Addr().String() | ||
} | ||
|
||
// TearDownSuite - runs once after all tests | ||
func (suite *OOBDialerTestSuite) TearDownSuite() { | ||
suite.server.Close() | ||
close(suite.dataChan) | ||
} | ||
|
||
// startTestServer - starts a test server and returns listener and data channel | ||
|
||
func startTestServer(t *testing.T) (net.Listener, chan []byte) { | ||
listener, err := net.Listen("tcp", "localhost:0") | ||
require.NoError(t, err, "Failed to create server") | ||
|
||
dataChan := make(chan []byte, 10) | ||
go func() { | ||
for { | ||
conn, err := listener.Accept() | ||
if err != nil { | ||
return | ||
} | ||
|
||
go func(conn net.Conn) { | ||
defer conn.Close() | ||
|
||
scanner := bufio.NewScanner(conn) | ||
for scanner.Scan() { | ||
line := scanner.Bytes() | ||
dataChan <- append([]byte{}, line...) | ||
break | ||
} | ||
|
||
if err := scanner.Err(); err != nil { | ||
t.Logf("Error reading data: %v", err) | ||
} | ||
}(conn) | ||
} | ||
}() | ||
|
||
return listener, dataChan | ||
} | ||
|
||
// TestDialStreamWithDifferentParameters - test data transmission with different parameters | ||
func (suite *OOBDialerTestSuite) TestDialStreamWithDifferentParameters() { | ||
tests := []struct { | ||
oobPosition int64 | ||
oobByte byte | ||
disOOB bool | ||
delay time.Duration | ||
}{ | ||
{oobPosition: 0, oobByte: 0x01, disOOB: false, delay: 100 * time.Millisecond}, | ||
{oobPosition: 0, oobByte: 0x01, disOOB: true, delay: 100 * time.Millisecond}, | ||
|
||
{oobPosition: 2, oobByte: 0x02, disOOB: true, delay: 200 * time.Millisecond}, | ||
{oobPosition: 2, oobByte: 0x02, disOOB: false, delay: 200 * time.Millisecond}, | ||
|
||
{oobPosition: int64(msgLen) - 2, oobByte: 0x02, disOOB: true, delay: 200 * time.Millisecond}, | ||
{oobPosition: int64(msgLen) - 2, oobByte: 0x02, disOOB: false, delay: 200 * time.Millisecond}, | ||
|
||
{oobPosition: int64(msgLen) - 1, oobByte: 0x02, disOOB: true, delay: 200 * time.Millisecond}, | ||
{oobPosition: int64(msgLen) - 1, oobByte: 0x02, disOOB: false, delay: 200 * time.Millisecond}, | ||
} | ||
|
||
for _, tt := range tests { | ||
suite.Run("Testing with different parameters", func() { | ||
ctx := context.Background() | ||
|
||
dialer := &transport.TCPDialer{ | ||
Dialer: net.Dialer{}, | ||
} | ||
oobDialer, err := NewStreamDialer(dialer, tt.oobPosition, tt.oobByte, tt.disOOB, tt.delay) | ||
|
||
conn, err := oobDialer.DialStream(ctx, suite.serverAddr) | ||
|
||
require.NoError(suite.T(), err) | ||
|
||
// Send test message | ||
message := []byte("Hello OOB!\n") | ||
n, err := conn.Write(message) | ||
require.NoError(suite.T(), err) | ||
assert.Equal(suite.T(), len(message), n) | ||
|
||
// Check that the server received the message | ||
receivedData := <-suite.dataChan | ||
assert.Equal(suite.T(), string(message[0:len(message)-1]), string(receivedData)) | ||
}) | ||
} | ||
} | ||
|
||
// TestOOBDialerSuite - main test suite | ||
func TestOOBDialerSuite(t *testing.T) { | ||
suite.Run(t, new(OOBDialerTestSuite)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
//go:build linux || darwin | ||
|
||
package oob | ||
|
||
import ( | ||
"golang.org/x/sys/unix" | ||
"net" | ||
"syscall" | ||
) | ||
|
||
const MSG_OOB = unix.MSG_OOB | ||
|
||
type SocketDescriptor int | ||
|
||
func sendTo(fd SocketDescriptor, data []byte, flags int) (err error) { | ||
return syscall.Sendmsg(int(fd), data, nil, nil, flags) | ||
} | ||
|
||
func getSocketDescriptor(conn *net.TCPConn) (SocketDescriptor, error) { | ||
file, err := conn.File() | ||
if err != nil { | ||
return 0, err | ||
} | ||
return SocketDescriptor(file.Fd()), nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the delay really needed? I found the TCP writes to be quite consistent and never had issues without the delay.
For simplicity, I would only add it if proven needed in Go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Delay is essential.
This is a little bit complex implementation in byeDPI that works only on linux. So now it is only delay.