-
Notifications
You must be signed in to change notification settings - Fork 94
feat: ✨ add new OutlineDevice API that uses Outline SDK #118
base: master
Are you sure you want to change the base?
Conversation
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.
Are you in the office tomorrow? perhaps we can brainstorm a bit on the api
@fortuna I will be in office on Wednesday, let me schedule a meeting. |
As discussed offline, @fortuna please take a look at the newly proposed |
|
||
func startLegacyShadowsocksClient() { | ||
// legacy raw flags | ||
config := shadowsocks.Config{ |
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.
Can you define a legacyConfigFromFlags()
, and pass the config as a parameter?
Making the config explicit in the function call will make the call more understandable.
Let's use "start tunnel" to be analogous to the new code.
I'm imagining startLegacyShadowsocksTunnel(legacyConfigFromClient)
return nil, nil, fmt.Errorf("failed to resolve proxy address: %w", err) | ||
} | ||
|
||
proxyTCPEndpoint := transport.TCPEndpoint{RemoteAddr: net.TCPAddr{IP: proxyIP.IP, Port: port}} |
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.
I suggest you pull the latest version of the SDK. This now takes a string. Example: https://github.com/Jigsaw-Code/outline-internal-sdk/blob/e79d369307d001859b3a4e2ecb0ecbf140a4f11f/examples/outline-connectivity/main.go#L132
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.
FYI: #120
Let me know of you want to merge that or not. It shouldn't conflict much.
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.
Sure, please merge that. BTW, I will work on the SDK change (to introduce IPDevice) before updating this PR as well.
config.Prefix = p | ||
} | ||
} | ||
client, err := shadowsocks.NewClient(&config) | ||
if err != nil { | ||
log.Errorf("Failed to create Shadowsocks client: %v", err) | ||
os.Exit(neterrors.IllegalConfiguration.Number()) | ||
} | ||
|
||
if *args.checkConnectivity { |
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.
Move this back out. The connectivity test and the tunnel flows are separate. We need to clearly run one or the other like we had before.
Also, don't we need a check connectivity with json config, for the udp update?
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.
We don't need any connectivity test for the new json config tunnel. I'd rather expose a public OutlineTunnel.IsUDPSupported()
method so the caller can retrieve that info.
if tunDev == nil { | ||
return nil, errors.New("tun device is required") | ||
} | ||
tn, err := newTunnelFromJSON(configJSON, tunDev) |
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.
We need a clearer name. Perhaps this?
tn, err := newTunnelFromJSON(configJSON, tunDev) | |
proxyTun, err := newTunnelFromJSON(configJSON, tunDev) |
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.
I agree. Tunnel
is a bad name, it's similar to tun device, which is very confusing.
outline/tun2socks/tunnel.go
Outdated
@@ -40,7 +44,7 @@ type Tunnel interface { | |||
} | |||
|
|||
// Deprecated: use Tunnel directly. | |||
type OutlineTunnel = Tunnel | |||
type OutlineTunnel Tunnel | |||
|
|||
type outlinetunnel struct { | |||
tunnel.Tunnel |
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.
Let's remove this. I don't really think it's needed, and it's extremely confusing. Let's see what breaks and fix it. I believe the comments here will address most issues.
tunnel.Tunnel |
// | ||
// This function does *not* take ownership of the TUN file descriptor `fd`; the | ||
// caller is responsible for closing after Tunnel disconnects. | ||
func ConnectTunnel(configJSON string, fd int) (Tunnel, error) { |
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.
The ConnectTunnel function is doing different things in different platforms. That is confusing. We need to fix that.
Can you make this take a ReadWriteCloser for the tun device and move this to the shared code?
if err != nil { | ||
return nil, err | ||
} | ||
tn, err := newTunnelFromJSON(configJSON, tunDev) |
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.
Remove tunDev
, and give a better name for the proxy tunnel:
tn, err := newTunnelFromJSON(configJSON, tunDev) | |
proxyTun, err := newTunnelFromJSON(configJSON) |
The initialization that needs tunDev
should happen below.
return nil, fmt.Errorf("unable to create tunnel from config: %w", err) | ||
} | ||
|
||
go tunnel.ProcessInputPackets(tn, tunDev) |
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.
Use CopyBuffer. See comment on Electron code, which should be shared.
return nil, fmt.Errorf("unable to create tunnel from config: %w", err) | ||
} | ||
|
||
go io.CopyBuffer(tn, tunDev, make([]byte, mtu)) |
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.
We need to see the copy both ways in the same place. This code only shows one way, which is confusing. Where's the flow from the tun device to the proxy device? It takes a lot of digging to figure that out.
I think we could implement the bridge like this:
go io.CopyBuffer(tn, tunDev, make([]byte, mtu)) | |
go func() { | |
defer proxyTun.Close() | |
io.CopyBuffer(proxyDevice, tunDev, make([]byte, mtu)) | |
} | |
go proxyTun.WriteTo(tunDev) |
The reason for WriteTo is to avoid a layer of buffers when possible.
proxyTun.WriteTo will effectively call core.RegisterOutputFn
to write to the tun device, Then wait for proxyTun.Close(). ProxyTun.Close()
should call lwipStack.Close()
. This way you don't need tunnel.Tunnel
anymore.
Outline Client is referencing the following APIs (Android JNI interface as an example) exported by `gomobile`. <img width="642" alt="image" src="https://user-images.githubusercontent.com/93548144/232151618-de7c91eb-2ee6-444e-bbe0-023262af2149.png"> But due to the recent refactoring, we introduced types that are not recognized by `gomobile`. This is the only function exported in `master` branch now: <img width="646" alt="image" src="https://user-images.githubusercontent.com/93548144/232152396-6cf278ab-f45b-448a-adb9-c03b13772eb7.png"> In this PR, I re-exported these functions (together with the new `NewClientFromJSON`) by using the built-in types. Here is the exported Android JNI interface: <img width="635" alt="image" src="https://user-images.githubusercontent.com/93548144/232151977-ad6bd330-4bc5-4383-b6ef-49dce4dc1853.png"> /cc @sbruens , although the required APIs are re-exported, some of the data types still need to be updated: * [`OutlineTunnel`](https://github.com/Jigsaw-Code/outline-client/blob/master/src/cordova/android/OutlineAndroidLib/outline/src/main/java/org/outline/vpn/VpnTunnel.java#L49) -> `Tunnel` * [`Tun2socksOutlineTunnel`](https://github.com/Jigsaw-Code/outline-client/blob/master/src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m#L39) -> `Tun2socksTunnel` Related PR: #118
In this PR, I added a new
OutlineDevice
API that can be used by Outline Client to replace the oldshadowsocks.CheckConnectivity
,shadowsocks.newClient
andOutlineTunnel
. I integrated Outline SDK into the implementation as well.I also refactored a bunch of things in this PR:
outline
package ingomobile
outline/**
sub packages as deprecatedRelated PR: #122 , #124