SOCKSサーバを標準ライブラリのみで実装する

## 初めに
この記事は、SOCKSサーバを標準ライブラリのみで実装する記事です。使用するライブラリを標準ライブラリだけに絞ることで、SOCKSプロトコルへの理解とRustへの理解の両方を狙いました。

## SOCKSとは
プロキシサーバとそれを実現するプロトコルの一種で、バージョン5に当たるSOCKS5というプロトコルが[RFC 1928](https://www.ietf.org/rfc/rfc1928.txt)で定義されています。
具体的には、TCPストリームをrelayすることによって、プロキシとしての機能を実現します。

例えば、ClientAがSOCKSサーバXを通してServerBにアクセスする場合、ClientAはまずXとTCPで接続を確立します。そこで、AがXにSeverBのIPアドレスを伝えます。すると、Xがその情報を元にBと接続を確立します。そして、Xが、Aから送られてきたデータをBへ送りつつ、Bから送られてきたデータをAへ送ります。

## 実装
今回はプロトコルがシンプルな[SOCKS4](http://hp.vector.co.jp/authors/VA017085/text/socks4.html)を実装します。

### TCPサーバ
SOCKSサーバを実装する上でまず必要なのはTCPサーバ、つまり、ソケットプログラミングでおなじみのbind、listen、acceptのループです。

bind + listen

```rust
let socks_address = "127.0.0.1:10334";
let listener;

match TcpListener::bind(socks_address) {
    Err(e) => {
        println!("Error: {}", e);
        exit(0);
    },
    Ok(l) => {
        listener = l;
    },
};
```
accept + コネクションを別スレッドでハンドル

```rust
loop {
    match listener.accept() {
        Err(e) => {
            println!("Error: {}", e)
        },
        Ok((stream, addr)) => {
            println!("Received request from {}", addr);
            // handle request in spawned thread
            thread::spawn(move || {
                println!("This is in spawned thread");
                handle_request(stream);                
            });
        }
    }
}
```

### TCPストリームからデータの読み出す
TCPストリームを流れてくるデータはただのバイト列なので、それを取り出し適切な形で解釈する関数が必要になります。1バイトでu8と解釈する関数、2バイトでu16と解釈する関数、nバイトで文字列と解釈する関数などです。

u8として解釈する関数

```rust
fn read_u8(s: &mut TcpStream) -> u8 {
    let mut buf: [u8; 1] = [0];

    s.read(&mut buf);
    return buf[0];
}
```
u16として解釈する関数

```rust
fn read_u16(s: &mut TcpStream) -> u16 {
    let mut buf: [u8; 2] = [0, 0];

    s.read(&mut buf);

    // two u8 to u16
    let data1 = buf[0] as u16;
    let data2 = buf[1] as u16;
    let data = data1 * 256 + data2;
    return data;
}
```
Stringとして解釈する関数

```rust
fn read_user(s: &TcpStream) -> String {
    let mut stream = s.try_clone().unwrap();
    let mut buf: [u8; 128] = [0; 128];
    let mut user = "".to_string();

    stream.read(&mut buf);

    for i in 1..128 {
        let ch = buf[i] as char;
        user.push(ch);
    };
    println!("user: {}", user);

    return user;
}
```

### 読み出したデータを処理する
バージョンや内容がプロトコルに沿っているかを確認し、繋ぎにいくべきアドレスなどを読み出します。

```rust
let (r, ver, cmd) = check_request(&client_stream);
    if !r {
        println!("Error: SOCKS request is not valid");
        return;
    }

let mut target_address;
if ver == 4 {
    match process_request_v4(&client_stream) {
        Ok(target) => {
            target_address = target;
        },
        Err(e) => {
            println!("Error: failed to process SOCKS requset");
            return
        },
    }
} else {
    println!("Error: SOCKS request is not valid");
    return;
}
```

### TCPストリームをrelayする
では実際にRustでどのようにこのrelayを実装するかというと、まず両方のTcpStreamをcloneし、それぞれ別スレッドで逆方向に、readしたデータをwriteでストリームに流してshutdownします。

```rust
let mut client_stream_c = client_stream.try_clone().unwrap();
let mut target_stream_c = target_stream.try_clone().unwrap();

// SeverB to ClientA
thread::spawn(move || {
    copy(&mut target_stream_c, &mut client_stream_c);
    target_stream_c.shutdown(Shutdown::Read);
    client_stream_c.shutdown(Shutdown::Write);
});

// ClientA to ServerB
copy(&mut client_stream, &mut target_stream);
target_stream.shutdown(Shutdown::Write);
client_stream.shutdown(Shutdown::Read);
```

### 実際に使用する
proxychainsもしくはブラウザのSOCKSプロキシ機能で確認します。

```:proxychains.conf
[ProxyList]
socks4 127.0.0.1 10334
```
```
sudo apt-get install proxychains
proxychains firefox
```

## 結論
標準ライブラリのみでも200行以下でSOCKSサーバを実装できるRustはすごい

## ソースコード
[GitHub - ak1t0/rust-socks-server](https://github.com/ak1t0/rust-socks-server)

## 参考文献
[SOCKS4](http://hp.vector.co.jp/authors/VA017085/text/socks4.html)
[GitHub - zmack/rust-socks: Socks5 server written in rust](https://github.com/zmack/rust-socks)