Shadowsocks-go Source Code Analysis

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Shadowsocks protocol

The Shadowsocks protocol packet format is the IV vector plus playload, which is the result of the encryption.

+-------+----------+|  IV   | Payload  |+-------+----------+| Fixed | Variable |+-------+----------+

After decryption for

+--------------+---------------------+------------------+----------+| Address Type | Destination Address | Destination Port |   Data   |+--------------+---------------------+------------------+----------+|      1       |       Variable      |         2        | Variable |+--------------+---------------------+------------------+----------+

The server-side decryption requires this IV vector and the original negotiated key to decrypt, after the handshake is complete, all subsequent TCP packets will not take the IV, but the one negotiated with the handshake when the IV.

SOURCE parsing

This analysis Shadowsocks-server source code, the overall process is:

    1. Monitoring Services

    2. Initializing cryptographic objects

    3. Decrypting client data

    4. Connecting to a remote host

    5. Establish a communication connection

Monitoring Services

Here, according to the configuration file, port monitoring, followed by the regular accept () waiting for the connection.

    for port, password := range config.PortPassword {        go run(port, password, config.Auth)        if udp {            go runUDP(port, password, config.Auth)        }    }

Initializing cryptographic objects

When there is a link coming after first check whether the secret object has been initially resolved, then encapsulate net. Conn. Here the cipher based on different encryption algorithm to implement the stream encryption and decryption Xorkeystream (DST, src []byte) interface, in particular, can see Golang comes with standard library cipher. Stream, of course, this interface to read the IV vector before it can be implemented.

        //如果没有初始化,解析初始化.        if cipher == nil {            log.Println("creating cipher for port:", port)            cipher, err = ss.NewCipher(config.Method, password)            if err != nil {                log.Printf("Error generating cipher for port: %s %v\n", port, err)                conn.Close()                continue            }        }        //这里要根据password产生key.        key := evpBytesToKey(password, mi.keyLen)

Decrypting client data

Net. Conn is encapsulated after the Read method reads the data is the decrypted data

func (c *Conn) Read(b []byte) (n int, err error) {    //如果解密接口没有实现,读取iv向量初始化解密接口.    if c.dec == nil {        iv := make([]byte, c.info.ivLen)        if _, err = io.ReadFull(c.Conn, iv); err != nil {            return        }        //读取到iv向量后就可以初始化解密接口        if err = c.initDecrypt(iv); err != nil {            return        }        if len(c.iv) == 0 {            c.iv = iv        }    }    //如果读取buff大于内置buff则分配内存    cipherData := c.readBuf    if len(b) > len(cipherData) {        cipherData = make([]byte, len(b))    } else {        cipherData = cipherData[:len(b)]    }        //读取数据后解密返回    n, err = c.Conn.Read(cipherData)    if n > 0 {        c.decrypt(b[0:n], cipherData[0:n])    }    return}

Connecting to a remote host

When the decrypted data is read, the unpacking is started and only the main code is copied.

    //这里判断一个字节的地址类型    addrType := buf[idType]    //这里根据地址类型的不同读取地址    if _, err = io.ReadFull(conn, buf[reqStart:reqEnd]); err != nil {        return    }    //这里读取2个字节的端口    port := binary.BigEndian.Uint16(buf[reqEnd-2 : reqEnd])    //当获取到地址和端口后调用dial连接远程主机    remote, err := net.Dial("tcp", host)

There may still be OTA data, depending on the OTA has been deprecated, it is no longer explained, interested students can check their own information.

Establish a communication connection

The communication connection here is a bit like using IO. Copy (), connecting two Conn respectively.

    //PipeThenClose有点像io.Copy    if ota {        go ss.PipeThenCloseOta(conn, remote)    } else {        go ss.PipeThenClose(conn, remote)    }    ss.PipeThenClose(remote, conn)    //PipeThenClose的原理就是不断读取然后写入,直到出错.    for{        n, err := src.Read(buf)        // read may return EOF with n > 0        // should always process n > 0 bytes before handling error        if n > 0 {            // Note: avoid overwrite err returned by Read.            if _, err := dst.Write(buf[0:n]); err != nil {                Debug.Println("write:", err)                break            }        }    }

Conclusion

Here the analysis of the source code of Shadowsocks-server, as well as shadowsocks-local feel the same thing is more than a cryptographic process.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.