Skip to content

Commit

Permalink
fix udp relay
Browse files Browse the repository at this point in the history
  • Loading branch information
paulzql committed Aug 9, 2017
1 parent f224aea commit e022cf6
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 39 deletions.
2 changes: 1 addition & 1 deletion lib/shadowsocks/protocol.ex
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ defmodule Shadowsocks.Protocol do
addr =
:erlang.tuple_to_list(addr)
|> :erlang.list_to_binary
case length(addr) do
case byte_size(addr) do
4 ->
<<@atyp_v4, addr::binary, port::16, data::binary>>
6 ->
Expand Down
33 changes: 16 additions & 17 deletions lib/shadowsocks/udp_relay.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ defmodule Shadowsocks.UDPRelay do
defp loop(lsock, encoder, parent) do
receive do
{:udp, ^lsock, caddr, cport, data} ->
client = {caddr, cport}
pid =
case Process.get({caddr, cport}) do
case Process.get(client) do
nil ->
p = spawn(fn -> init_conn(lsock, encoder, parent) end)
Process.put({caddr, cport}, p)
{p,_} = spawn_monitor(fn -> init_conn(lsock, encoder, parent, client) end)
Process.put(client, p)
Process.put(p, client)
p
pid ->
pid
Expand All @@ -35,13 +37,20 @@ defmodule Shadowsocks.UDPRelay do
loop(lsock, encoder, parent)
:stop ->
:stop
{:DOWN, _, :process, pid, _} ->
with {addr, port} <- Process.get(pid) do
Process.delete(pid)
Process.delete({addr, port})
end
loop(lsock, encoder, parent)
_ ->
loop(lsock, encoder, parent)
end
end

defp init_conn(lsock, encoder, parent) do
conn_loop(lsock, encoder, %{parent: parent, down: 0, up: 0})
defp init_conn(lsock, encoder, parent, {addr, port}) do
{:ok, socket} = :gen_udp.open(0, [:binary, {:active, :once}])
conn_loop(lsock, encoder, %{parent: parent, down: 0, up: 0, socket: socket, addr: addr, port: port})
end

defp conn_loop(lsock, encoder, %{parent: pid, down: down, up: up})
Expand All @@ -57,22 +66,12 @@ defmodule Shadowsocks.UDPRelay do
|> Encoder.decode_once(data)
|> Shadowsocks.Protocol.unpack

socket =
case Process.get({addr, port}) do
nil ->
{:ok, socket} = :gen_udp.open(0, [:binary, {:active, :once}])
Process.put({addr, port}, socket)
socket
socket ->
socket
end

:gen_udp.send(socket, addr, port, data)
:gen_udp.send(arg.socket, addr, port, data)
conn_loop(lsock, encoder, arg)

{:udp, sock, addr, port, data} ->
data = Shadowsocks.Protocol.pack(addr, port, data)
:gen_udp.send(lsock, addr, port, Encoder.encode_once(encoder, data))
:gen_udp.send(lsock, arg.addr, arg.port, Encoder.encode_once(encoder, data))
:inet.setopts(sock, active: :once)
conn_loop(lsock, encoder, arg)

Expand Down
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Shadowsocks.Mixfile do

def project do
[app: :shadowsocks,
version: "0.3.0",
version: "0.3.1",
elixir: "~> 1.4",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
Expand All @@ -29,7 +29,7 @@ defmodule Shadowsocks.Mixfile do

# Dependencies can be Hex packages:
#
# {:my_dep, "~> 0.3.0"}
# {:my_dep, "~> 0.3"}
#
# Or git/path repositories:
#
Expand Down
45 changes: 26 additions & 19 deletions test/encoder_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule EncoderTest do
@pass "mypassword-test-hello-world,01234567890"

test "bad methods" do
assert_raise FunctionClauseError, fn -> Encoder.init("bad-method", "sss") end
assert_raise MatchError, fn -> Encoder.init("bad-method", "sss") end
end

test "init" do
Expand All @@ -18,33 +18,40 @@ defmodule EncoderTest do
test "rc4-md5" do
e = Encoder.init("rc4-md5", @pass)
{e, d} = Encoder.encode(e, @data)
{_, d} = Encoder.decode(e, d)
{_, d} = e |> Encoder.init_decode(e.enc_iv) |> Encoder.decode(d)
assert @data == d
end

test "tt" do
e1 = Encoder.init("aes-128-cfb", @pass)
e2 = Encoder.init("aes-128-cfb", @pass) |> Encoder.init_decode(e1.enc_iv)

{_, d1} = Encoder.encode(e1, @data)
{_, d2} = Encoder.decode(e2, d1)
assert d2 == @data
end
test "aes-128-cfb" do
e = Encoder.init("aes-128-cfb", @pass)
{e, d} = Encoder.encode(e, @data)
{_, d} = Encoder.decode(e, d)
e1 = Encoder.init("aes-128-cfb", @pass)
e2 = Encoder.init_decode(e1, e1.enc_iv)
{_, d} = Encoder.encode(e1, @data)
{_, d} = Encoder.decode(e2, d)
assert @data == d
end

test "aes-256-cfb" do
e = Encoder.init("aes-256-cfb", @pass)
{e, d} = Encoder.encode(e, @data)
<<iv::binary-size(16), d::binary>> = d
{_, d} = e |> Encoder.init_decode(iv) |> Encoder.decode(d)

e1 = Encoder.init("aes-256-cfb", @pass)
e2 = Encoder.init_decode(e1, e1.enc_iv)
{_, d} = Encoder.encode(e1, @data)
{_, d} = Encoder.decode(e2, d)
assert @data == d
end

test "decode from other app" do
origin = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
e = Encoder.init("aes-256-cfb", "mypass")
<<d3::binary-size(20), d4::binary>> = File.read!("test/50F_aes256cfb.data")
{e, r3} = Encoder.decode(e, d3)
{_, r4} = Encoder.decode(e, d4)
IO.inspect r3
assert origin == <<r3::binary, r4::binary>>
end
# test "decode from other app" do
# origin = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
# <<iv::binary-size(16), d4::binary>> = File.read!("test/50F_aes256cfb.data")
# e = Encoder.init("aes-256-cfb", "mypass") |> Encoder.init_decode(iv) |> IO.inspect
# {_, r4} = Encoder.decode(e, d4)

# assert origin == r4
# end
end
37 changes: 37 additions & 0 deletions test/udp_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
defmodule UDPRelayTest do
use ExUnit.Case
alias Shadowsocks.Encoder
alias Shadowsocks.Protocol

@data <<"test hello world", 10, 0, 20, "ok">>
@pass "mypassword-test-hello-world,01234567890"
@method "aes-128-cfb"
@addr {192,168,11,23}
@port 20201

test "test encode once" do
data =
Encoder.init(@method, @pass)
|> Encoder.encode_once(@data)
data2 =
Encoder.init(@method, @pass)
|> Encoder.decode_once(data)

assert @data == data2
end

test "encode and pack" do
data =
Encoder.init(@method, @pass)
|> Encoder.encode_once(Protocol.pack(@addr, @port, @data))

{addr, port, data2} =
Encoder.init(@method, @pass)
|> Encoder.decode_once(data)
|> Protocol.unpack

assert @addr == addr
assert @port == port
assert @data == data2
end
end

0 comments on commit e022cf6

Please sign in to comment.