Shadowsocks-workerman-php UDP support added
原来workerman 实现的 shadowsocks 服务器仅支持 TCP,不支持 UDP,这样导致无法直接兼容 OUTLINE 客户端,网上找了一些资料,主要参考了 swoole-ss 这方面的实现,最终实现了 UDP 支持,顺便兼容 OUTLINE。
以下为修改 server.php 的内容
- 增加 UDP 监听
// 初始化worker,监听$PORT端口
$worker = new Worker('tcp://0.0.0.0:'.$PORT);
$worker2 = new Worker('udp://0.0.0.0:'.$PORT);
// 进程数量
$worker->count = $PROCESS_COUNT;
$worker2->count=$worker->count = $PROCESS_COUNT;
// 名称
$worker->name = 'shadowsocks-server';
$worker2->name=$worker->name = 'shadowsocks-server';
// UDP support
$worker2->onMessage=function($connection, $buffer)use($METHOD, $PASSWORD)
{
if (is_null(@$connection->encryptor)){
$connection->encryptor = new Encryptor($PASSWORD, $METHOD);
}
$buffer = $connection->encryptor->decrypt($buffer);
// 解析socket5头
$header_data = parse_socket5_header2($buffer);
// 头部长度
$header_len = $header_data[3];
$host = $header_data[1];
$port = $header_data[2];
$address = "udp://$host:$port";
//echo $address."\n";
$remote_connection = new AsyncUdpConnection($address);
@$remote_connection->source=$connection;
$remote_connection->onConnect=function ($remote_connection)use ($buffer,$header_len){
$remote_connection->send(substr($buffer,$header_len));
};
$remote_connection->onMessage=function ($remote_connection,$buffer)use($header_data){
$_header = pack_header($header_data[1],$header_data[0],$header_data[2]);
$_data = $remote_connection->source->encryptor->encrypt($_header.$buffer);
$remote_connection->source->send($_data);
};
$remote_connection->connect();
};
/*
UDP 部分 返回客户端 头部数据 by @Zac
//生成UDP header 它这里给返回解析出来的域名貌似给udp dns域名解析用的
*/
function pack_header($addr,$addr_type,$port){
$header = '';
//$ip = pack('N',ip2long($addr));
//判断是否是合法的公共IPv4地址,192.168.1.1这类的私有IP地址将会排除在外
/*
if(filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE)) {
// it's valid
$addr_type = ADDRTYPE_IPV4;
//判断是否是合法的IPv6地址
}elseif(filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE)){
$addr_type = ADDRTYPE_IPV6;
}
*/
switch ($addr_type) {
case ADDRTYPE_IPV4:
$header = b"\x01".inet_pton($addr);
break;
case ADDRTYPE_IPV6:
$header = b"\x04".inet_pton($addr);
break;
case ADDRTYPE_HOST:
if(strlen($addr)>255){
$addr = substr($addr,0,255);
}
$header = b"\x03".chr(strlen($addr)).$addr;
break;
default:
return;
}
return $header.pack('n',$port);
}
项目代码: https://github.com/firzen/shadowsocks-php
参考:
https://github.com/walkor/shadowsocks-php
https://github.com/shadowsocksBak/shadowsocks-php