分类 其他 下的文章

SS通讯步骤

目前在写一个Socks5转SS的工具(某些奇怪需求需要), 在互联网上翻了几个网站并没有详细说明SS通讯步骤. 所以在这记录下.

密码初始化

本文章aes-256-cfb加密来说明, 当使用AES时需要提供KeyIV(初始化向量). 其中IV类似于给hash加盐, 不过这个盐是基于上一个数据块加密后的出来的盐. 那为啥还需要提供IV呢?因为第一次用的时候没上一块数据只能自己指定一个.

SS生成KeyIV是基于用户指定的密码来生成的, 以下为TypeScript基于密码生成KeyIV代码:

function generateKeyIVByPassword(passwordString: string, keyLength: number, ivLength: number): any {
    var password = new Buffer(passwordString, "binary");
    var hashBuffers: Array<Buffer> = [];
    for (var dataCount = 0, loopCount = 0; dataCount < keyLength + ivLength; loopCount++) {
        var data: any = password;
        if (loopCount > 0) {
            data = Buffer.concat([hashBuffers[loopCount - 1], password]);
        }
        var md5 = crypto.createHash("md5");
        var md5Buffer = md5.update(data).digest();
        hashBuffers.push(md5Buffer);
        dataCount += md5Buffer.length;
    }
    var hashBuffer: Buffer = Buffer.concat(hashBuffers);
    return {
        key: hashBuffer.slice(0, keyLength),
        iv: hashBuffer.slice(keyLength, keyLength + ivLength)
    };
}

从上述代码中可以得知SS作者先将用户指定的密码迭代MD5多次; 其结束条件是迭代多次的MD5结果长度相加, 如果长度大于加密算法所需Key长度 + IV长度则退出循环. 最后将MD5 Hash结果截断来获得KeyIV.

通讯过程(TCP过程)

当客户端连接至服务端后会直接发送 客户端IV + 已被加密的Socks5头 + TCP数据.

IV交换

Client连接后, Client发送的第一个数据前N个字节(取决于加密算法)是AESIV用于来解密来自Client的数据.
然后Server发送Client的第一个数据也是类似. 其结构图如下:
ShadowsocksIVED.png

注意!SS中这样交换IV是不安全做法.

通讯

SS省略了Socks5协商过程直接进入通讯过程. Socks5通讯需要客户端提供 目标IP或域名 + 端口. 当客户端提供完成之后服务端会连接至目标IP并返回是否连接成功; 如果连接成功就能够直接通讯了.

格式如下:
027071B4-415D-4ACE-BF39-EFABB2F7B64A.png

上述说过SS省略了协商过程, 所以这里Socks5请求也是缩水的. 其把前3个字节砍掉了, 也就是说Client只会发来ATYP, DST ADDR, DST PROT. 当连接至DST ADDRDST ADDR发送的数据加密发送给Client, Client发送的数据解密发送给DST ADDR. 这样SS就完成了通讯.

参考资料

批量将MyISAM引擎转换为InnoDB引擎

<?php
header('Content-type: text/html;charset=utf-8');
@error_reporting(E_ALL | E_STRICT);
@ini_set('display_errors', '1');

//填写数据库IP地址, 账号, 密码
$con = mysql_connect('127.0.0.1', 'root', 'root');
//填写需要转换的数据库名字
$dbName = 'minecraft_status';

$sql = "SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '$dbName' AND ENGINE = 'MyISAM';";
$rs = mysql_query($sql, $con);

$count = 0;
$ok = 0;
while($row = mysql_fetch_array($rs))
{
    $count ++;
    $tbl = $row[0];
    $sql = "ALTER TABLE $dbName.$tbl ENGINE = INNODB;";
    $resultado = mysql_query($sql);
    if ($resultado){
        $ok ++;
        echo $sql."<hr/>";
    }
}
if ($count == $ok)
{
    echo '<div style="color: green"><b>全部表转换成功</b></div>';
}else{
    echo "<div style=\"color: red\"><b>出现错误</b>表的数量: $count, 成功转换的数量: $ok</div>";
}

MWC飞控通讯

前几个星期入手了一款基于MWC飞控的WIFI小四轴,缺点就是只有手机APP。操作起来没有手感。寻思着用Ardiuno+C#做一个实体遥控器。首先是封装MWC通讯格式,下面就是封装的代码。最后结局就是手滑没调好撞废一个硬盘

/// <summary>
/// 获取发送Byte
/// </summary>
/// <param name="command">操作</param>
/// <param name="data">数据</param>
/// <returns></returns>
public byte[] GetFlyByte(int command, int[] data)
{
    byte[] FlyByte = new byte[data.Length + 6];
    // $
    FlyByte[0] = (byte)Convert.ToInt32("24", 16);
    // M
    FlyByte[1] = (byte)Convert.ToInt32("4D", 16);
    // <
    FlyByte[2] = (byte)Convert.ToInt32("3C", 16);
    //数据长度
    FlyByte[3] = (byte)Convert.ToInt32(data.Length.ToString("X"), 16);
    //操作
    FlyByte[4] = (byte)Convert.ToInt32(command.ToString("X"), 16);
    
    byte[] ConvertData = new byte[data.Length];
    //发送数据赋值 与 校验数据赋值
    for (int i = 5, j = 0; i < data.Length + 5; i++, j++ )
    { 
        FlyByte[i] = (byte)data[j];
        ConvertData[j] = (byte)data[j];
    }

    FlyByte[FlyByte.Length-1] = CheckNumber((byte)command, ConvertData);
    return FlyByte;
}

/// <summary>
/// 获取校验码
/// </summary>
/// <param name="command">操作</param>
/// <param name="data">数据</param>
/// <returns>校验码</returns>
private byte CheckNumber(byte command, byte[] data)
{
    byte rdata = 0;

    rdata ^= (byte)(data.Length & 0xFF);
    rdata ^= (byte)(command & 0xFF);

    for (int i = 0; i < data.Length; i++)
        rdata ^= (byte)(data[i] & 0xFF);

    return rdata;
}

flyc.jpg
MWC通讯格式官方文档:http://www.multiwii.com/wiki/index.php?title=Multiwii_Serial_Protocol

第一次PHP面试小记

上来先问了 第一次 浏览器 访问 输出结果 和 第二次 浏览器访问 输出结果

setcookie('a', '123');
echo $_COOKIE['a'];

第一次浏览器 发送了请求但是 在请求的HTTP头内 Cookie 是空所以 输出的是空

第二次浏览器 已经在第一次的上面收到了服务端要设置 Cookie 的消息 所以浏览器里已经有 Cookie 了 这下浏览器发送HTTP请求头里已经包含 Cookie 了 所以可以输出了123


然后问了 Session 和 Cookie 的区别这个也是基础,但是我回答到最后补充了一句 "也可以学习CI保存'Session'的方法 把 Session 当 Cookie 用" 面试官吐槽说这样不安全 讨论了较长的一段时间。


接着问 Session 保存在哪 存储方式 以及和那个存储方式比较好

答完 Session 问题后面试官画了一个很简单的表类似:
test table
a b c
1 2 3
4 5 6
7 8 9

select * from `test` where a = 1 and b = 2
select * from `test` where b = 2 and a = 1

问这两个语句有性能上的区别吗 想了下应该没有性能上的区别。

然后就是问数据库咋搞性能比较高啊 回答 能分表尽量分 选择合适的Mysql数据库引擎 添加索引 有条件做主写从读库。

唯一说错了 客户端IP 不是放在HTTP头里的

搞定技术后 人事部的来谈薪资 我写的3000~4000 人事部说就3500吧 接着就完事了。就是刚出公司10分钟 人事打电话过来说年龄太小了 可以等到11月再去。