Chinaunix
标题:
Perl实现花生壳DDNS客户端[2010/12/01更新]
[打印本页]
作者:
coolend
时间:
2010-11-30 10:48
标题:
Perl实现花生壳DDNS客户端[2010/12/01更新]
本帖最后由 coolend 于 2010-12-01 20:01 编辑
花生壳相比大家都知道吧,在国内的用户群非常广泛,其协议已经公开了(似乎有段时间了)
相关协议说明可以参考:
http://open.oray.com/wiki/doku.p ... 1%E9%83%A8%E5%88%86
有位 “笑行天下” 的仁兄已经开发出C写的客户端,其博客地址为
http://blog.a1983.com.cn/?page_id=483
源代码下载地址:
http://blog.a1983.com.cn/software/ddns-r257-src.tar.gz
闲着没事,想研究下用Perl来实现,呵呵~~ 能力有限,对C不懂哦,所以先抛个砖,希望感兴趣的兄弟指点指点或一起来参与
验证过程如下:
客户机发出AUTH authtype指令,authtype为一种验证类型,我们这里使用AUTH ROUTER6(CRAM-MD5扩展)验证。
服务器回应一个挑战串,该串使用客户机的IP地址、服务器的当前时间等不可重复不可预测的参数生成,服务器使用BASE64方式将该串返回客户机,回应码为334
客户机将挑战串作为key使用CRAM-MD5的单向加密方式加密自己的密码形成加密串,
将账号和加密串作为回应,其格式为:
账号名+一个空格+加密嵌入认证码+客户端信息+加密串
其中,加密嵌入认证码共4个字节,为嵌入认证码与服务器当前时间运算得到,服务
器时间是挑战串的第六字节后的4个字节,算法是嵌入认证码与该时间的取反进行或
运算后循环右移一定位数;该右移位数是用服务器时间整除30;
客户端信息也是4个字节,前两位为嵌入式的客户号,后两位为客户端版本号;
客户机使用base64方式对回应进行编码返回服务器。
#!/usr/bin/perl
use strict;
use IO::Socket::INET;
use MIME::Base64 qw(encode_base64 decode_base64);
use Digest::HMAC_MD5 qw(hmac_md5);
my $serverip = "ph051.oray.net";
my $port = '6060';
### 登录用户名和密码
my $user = 'songgongzi';
my $pass = 'QrhxS25V';
my $sock = IO::Socket::INET->new(
PeerAddr => $serverip,
PeerPort => $port,
Proto => 'tcp',
) or die "ERR: unable to connect to server $! \n";
my $msg;
$sock->recv($msg,128);
die "ERR: server not response ! \n" if (! $msg);
print $msg;
## 发送验证请求
print $sock "auth router6\n";
$sock->recv($msg,128);
print $msg;
## BASE64 解码
$msg =~ s/^\d+\s+//;
my $reply = decode_base64($msg);
print "Reply message content is: ",unpack("H*",$reply),"\n";
## 服务器时间是挑战串的第六字节后的4个字节
my $stime = substr($reply,6,4);
my $tm_stime = unpack("H*",$stime);
$tm_stime =~ s/^(\w{2})(\w{2})(\w{2})(\w{2})$/$4$3$2$1/;
$tm_stime = hex($tm_stime);
## 打印下服务器的时间,便于调试
print "Server time is $tm_stime, ",&timenow($tm_stime),"\n";
### 以下信息从 “笑行天下” 的 DDNS代码中借用的
my $client_ID = "0x26A0"; # 客户端ID
my $client_VER = "0x9899"; # 客户端版本
my $auth_KEY = "0x1E0808B7"; # 嵌入认证密码
### 客户端信息为客户端ID+版本号,共4字节
my $client_info = ((hex($client_ID) & 0xFFFF) << 16) | (hex($client_VER) & 0xFFFF);
## 转换为16进制
$client_info = sprintf ("%x",$client_info);
$client_info =~ s/^(\w{2})(\w{2})(\w{2})(\w{2})$/$4$3$2$1/;
print "Client INFO: $client_info\n";
my $auth_key = hex($auth_KEY);
## 嵌入认证码与时间的取反进行或运算后循环右移
$tm_stime = $tm_stime | (~$auth_key);
print "DBG1: $tm_stime\n";
### 右移位数是用服务器时间整除30后的余数
my $mv = $tm_stime % 30;
print "Move count is $mv\n";
### 加密嵌入认证码
my $auth_enc = $tm_stime << ((32 - $mv) & 0x0000001F);
$auth_enc |= ($tm_stime) >> ($mv & 0x0000001F);
$auth_enc = sprintf ("%x",$auth_enc);
$auth_enc =~ s/^(\w{2})(\w{2})(\w{2})(\w{2})$/$2$1$4$3/;
print "AUTH_ENC: $auth_enc\n";
## 加密串
my $enc_str = unpack("H*",hmac_md5($pass, $reply));
print "ENC STR: $enc_str\n";
my $header = pack("H*","$auth_enc$client_info$enc_str");
print "HEADER: " . unpack("H*",$header) , " LEN: " , length($header),"\n";
## 生成回应串用BASE64编码
my $lines = join('',$user,' ',$header);
my $base64 = encode_base64 $lines;
print "Send BASE64: $base64\n";
### 发送给服务端
print $sock "$base64\n";
$sock->recv($msg,128);
print $msg;
### 注册域名
print $sock "regi a songgongzi.gicp.net\n";
$sock->recv($msg,128);
print $msg;
## 退出
print $sock "quit\n";
$sock->shutdown(1);
$sock->close();
sub timenow {
my $tm = time();
my ($sec,$min,$hur,$day,$mon,$year) = (localtime($tm))[0,1,2,3,4,5];
$year += 1900; ++ $mon ;
$mon = "0$mon" if (length($mon) < 2);
$day = "0$day" if (length($day) < 2);
$hur = "0$hur" if (length($hur) < 2);
$min = "0$min" if (length($min) < 2);
$sec = "0$sec" if (length($sec) < 2);
return "$year-$mon-$day $hur:$min:$sec";
}
复制代码
运行时,有时候可以成功,有时候验证失败,经反复测试,发现是加密嵌入认证码计算的问题,还有待进一步研究。
** 2010/12/01日更新
失败时的输出信息:
220 oray.cn DDNS ServerX6 Ready.
334 O6/XGgm6Kpn1TCvpouKvog==
Reply message content is: 3bafd71a09ba2a99f54c2be9a2e2afa2
Server time is 1291163946, 2010-12-01 08:41:12
Client INFO: 9998a026
DBG1: 3992452970
Move count is 20
AUTH_ENC: f67fdfae
ENC STR: ce08450f2eac389b3e7207acc9d852b3
HEADER: f67fdfae9998a026ce08450f2eac389b3e7207acc9d852b3 LEN: 24
Send BASE64: c29uZ2dvbmd6aSD2f9+umZigJs4IRQ8urDibPnIHrMnYUrM=
535 Authentication failure
500 Command unrecognized
成功时的输出信息:
220 oray.cn DDNS ServerX6 Ready.
334 O64u4vKL7Dj2TP8NEF1ZwQ==
Reply message content is: 3bae2ee2f28bec38f64cff0d105d59c1
Server time is 1291204844, 2010-12-01 20:02:05
Client INFO: 9998a026
DBG1: 3992453100
Move count is 0
AUTH_ENC: f7edecff
ENC STR: f1caf2faa67d45a46de09ed330567568
HEADER: f7edecff9998a026f1caf2faa67d45a46de09ed330567568 LEN: 24
Send BASE64: c29uZ2dvbmd6aSD37ez/mZigJvHK8vqmfUWkbeCe0zBWdWg=
250 Auth passed at level <0>
songgongzi.gicp.net
.
250 Register successfully
原来昨天晚上调试到后来花生壳的服务连接不上,是因为遭到了攻击,汗!树大招风阿
http://www.oray.com/news/420.html
作者:
黑色阳光_cu
时间:
2010-11-30 12:04
这个协议跟SMTP协议很像,可以拿Net::SMTP改。UI可以用Win32::GUI Tk Gtk2
作者:
wfnh
时间:
2010-11-30 13:07
这个协议跟SMTP协议很像,可以拿Net::SMTP改。UI可以用Win32::GUI Tk Gtk2
黑色阳光_cu 发表于 2010-11-30 12:04
改成一个POE组件也很好的说
作者:
coolend
时间:
2010-11-30 21:24
貌似最近免费版的花生壳服务最近不大稳定,一会儿连得上,一会儿又连不了,甚至连 open.oray.net 也打不开了
请版主,大伙帮忙分析分析,看看问题出在哪, Perl 的左移右移和C似乎有点不一样,上述移位的代码是参考C里面的,但有时候可以通过验证,这就奇怪了
谢谢各位啦~~~
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2