存档

2010年2月 的存档

飞信2010登录协议分析

二月 27th, {2010 17 条评论 17,865 人阅读过  

飞信2010出了有一段时间了,但到现在也只是beta版,所以就没怎么关注它,今天下载了一个分析了一下它的协议,才发现飞信迟迟不推出新版本是因为它的协议有了比较大的变动,似乎想要把我们这些山寨货赶尽杀绝,也就是传说中的V4版本的协议,很多信令后面都加上了V4标志,这也意味着想要适应2010,协议部分就必须重写。

飞信的登录协议比以前的版本有了显著的变化,最明显的变化在于它对登录信息的加密处理上,旧版本的飞信登录信息的加密让人看起来有点小儿科,把几个字段这样加起来做散列,然后再那样加起来做散列,来来回回折腾最后得出一个response传回服务器验证。

2010的登录信息处理采用了非对称加密RSA算法。先贴几个抓出来的协议包吧:
1.SSI登录
SSI登录仍然采用了https登录,登录服务器应该没变,还是uid.fetion.com.cn。登录参数变了,加上必须的参数uri如下:

https://uid.fetion.com.cn/ssiportal/SSIAppSignInV4.aspx?mobileno=1348888888&&domains=fetion.com.cn%3bm161.com.cn%3bwww.ikuwa.cn&&v4digest-type=2&v4digest=password

注意:这里的密码也不再是v3里面的明文密码了,呵呵。

其中demains里面有三个域名,第一个应该是必须的,后两个不知道是哪家第三方的公司的域名,估计可以去掉,v4digest-type是密码类型,有如下定义:

1
2
3
4
5
6
public enum PasswordTypeEnum
{
    V3,
    V4Temp,
    V4
}

v4digest就是密码了,然后还有一些可选参数像algorithm之类的我也就没细看它的功能。

2.sipC注册

R fetion.com.cn SIP-C/4.0
F: 916098834
I: 1
Q: 1 R
CN: 1CF1A05B2DD0281755997ADC70F82B16
CL: type=”pc” ,version=”3.6.1900″

这是sipC注册信息,CN就是旧版本里的cnouce , CL就是客户端信息了。服务器收到后回复信令:

SIP-C/4.0 401 Unauthoried
F: 916098834
I: 1
Q: 1 R
W: Digest algorithm=”SHA1-sess-

v4″,nonce=”389CE97D594B290366DCD4CC2DA5368D”,key=”D84CA40D849FEF3B45F02BBA6900D2A1B3010001″,signature=”62F5BA9D9146D477CDECAE1FD47098D0CABBFD31D683B5223B5D52″

为了节约篇幅key和signature的内容我都删去了一部分,key就是共享密钥,这个用来对验证信息做非对称加密用的,signature是签名,用来对密钥信息做验证的。

3.sipC验证

R fetion.com.cn SIP-C/4.0
F: 916098834
I: 1
Q: 2 R
A: Digest

response=”5041619340F10D101149E45A8E2343294E8D5F4F5086C24703EE00CAA4DF8F9D2951E9F285C458F556

7454F5C35084A8CB7C5E3AA8D31D1FC3B9DD7CF395631E5EDE73E2E683D54C9E521443D31792E18B81CA26542BF5

79F662459CD5F6E4C0EC29767B6C5F775C10AF19B544B6957AC98FF6A420C7486BE68837A576036118″,algorith

m=”SHA1-sess-v4″
AK: ak-value
L: 426

消息体里面的xml信息就不贴出来了。最关键的部分是通信sipC注册返回的信息来计算这个response,计算response共需要用到4个参数,publickey,nouce,password,aeskey.

publickey刚才注册返回的key值。

nouce 注册返回的nouce值。

password用户密码。

aeskey 用户通过 Rijndael算法生成的AES串。

response的计算规则是:

1.str = nouce + password + aeskey

2.对str进行RSA非对称加密,RSA算法具体细节我不懂,不过查看了一个微软MSDN了也大体知道是怎么工作的,它在计算的时候需要Exponent(e,公钥指数),Modulus(n , 模),D (d , 私钥指数),不过我看飞信在传递RSA参数的时候只是指定了e和n,e是截取了公钥的前256的字符,n是截取了公钥的256个以后的字符。

3.通过2计算出来的参数对str进行加密,得到的就是response值。

将验证信令发送到服务器之后服务器会返回用户的详细信息,这与之前的版本之比也是一大改进,省去了再额外构造信令去GetPersonalInfo

另外,新版本的协议在获取用户信息上改动也很大,sipC验证完成后用户个人信息和联系人列表就会随返回消息一同发过来,旧版本会先发送GetContactList信息获取用户列表,然后再构造一个庞大的Subscription去订阅这些用户的消息,新版本将这些完全简化了,发送如下一条信令就可以订阅所有用户的信息,用户信息就会被一条一条地推送过来。

SUB fetion.com.cn SIP-C/4.0
F: 916098834
I: 8
Q: 1 SUB
N: PresenceV4
L: 95

<args>
<subscription self="v4default;mail-count" buddy="v4default" version="320595567" />
</args>

格式如下:

BN 916098834 SIP-C/4.0
N: PresenceV4
I: 1
L: 190
Q: 5 BN

<events>
    <event type="PresenceChanged">
        <contacts>
            <c id="601820518"><pr di="" b="0" d="" dt="" dc="0"/></c>
            <c id="464997176"><pr di="" b="0" d="" dt="" dc="0"/></c>
        </contacts>
    </event>
</events>

将字段名称也简化了,这样有助于在数据传输时候节省字节数,效率会更高一些。

OK,重要的变化差不多也就这些了,真要动手去写的话也够我忙活一阵子的了,现在没那么多时间了,要老老实实专心做项目了,2010到现在也只是个beta版,我先静观其变吧,免得做无用功。

分类: Protocol 标签: , ,

Automake生成Makefile过程简介

二月 26th, {2010 1 条评论 11,013 人阅读过  

有校友在byr上看了我发的openfetion,发信息问我关于automake的东西,其实我了解的也并不多,只是自己查了些资料,然后借鉴了一下别人的项目中相关文件的写法,于是就想照着openfetion中的相关文件把自己对它的理解简单写一下,算是整理一下学过的知识,以后也好有个参考。
Automake支持三种目录层次:flat,shadow,deep
1.flat 所有的源文件及相关文件都放在顶层目录中。
2.shadow 主要的源文件存放在顶层目录中,其它的存放在各个子目录中。
3.deep 所有的源文件都分别存放在各个子目录中。

我的程序用了deep模式,所有的源文件都放在了src目录中。下面写一下automake生成Makefile的步骤:
1.运行autoscan命令,生成configure.scan。

configure.scan就是configure.in的模板,对它做一些修改,然后改名为configure.in或者configure.ac就可以了(新版本的automake好像是configure.ac)。
configure.in:

AC_INIT(src/openfetion.cpp)
AM_INIT_AUTOMAKE(openfetion,0.1)
AM_CONFIG_HEADER(config.h)
AM_PATH_GTK_2_0(,,AC_MSG_ERROR(openfetion 0.1 needs GTK+ 2.0))
AM_PATH_XML2(,,AC_MSG_ERROR(openfetion 0.1 needs LIBXML2))
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_OUTPUT(src/Makefile)
AC_INIT宏以任何一个源文件作为参数,它只是检查这个源文件的存在,也说意味着着源文件所在的目录存在
AM_INIT_AUTOMAKE 增加了几个标准的检查,它以程序名称和版本号作为参数
AC_PROG_CC 指出源代码可能是用C写的,如果源代码是用C++写的我们就需要AC_PROP_CXX
AC_PROG_INSTALL 会生成一个install目录文件,这样用户就可以通过输入“make install”来安装这个软件
AC_OUTPUT 指出将会生成的Makefile文件的名字
AC_CONFIG_HEADER 表示将会使用config.h文件,autoconf需要一个config.h.in文件,用它来生成config.h,config.h.in可以通过autoheader工具生成
AM_PATH_GTK_2_0(,,AC_MSG_ERROR(openfetion 0.1 needs GTK+ 2.0))
AM_PATH_XML2(,,AC_MSG_ERROR(openfetion 0.1 needs LIBXML2)) 这两句话检查系统中是否安装了程序所需要共享库, GTK+2.0和libxml2,这两个库在安装的时候分别安装了AM_PATH_GTK_2_0和 AM_PATH_XML2这两个宏,所以可以用这种方法检测,如果系统中没有安装libxml2,configure脚本就会执行失败,并报错:openfetion 0.1 needs LIBXML2
关于library的检查可参见文章:Using C/C++ libraries with Automake and Autoconf

其它的就不详细说了,需要的时候可以谷歌。
2.在顶层目录中创建一个Makefile.am,在其它各级需要的子目录中也创建Makefile.am。

我的顶层目录Makefile.am中只有下面几句话:

1
2
3
4
5
6
7
8
9
10
#子目录变量,用于递归处理各级子目录
SUBDIRS=src
#安装路径,可使用./configure --prefix=/usr/local/openfetion修改
prefix=/usr/local
#数据文件的安装路径
datadir=$(prefix)/skin
#数据文件的具体内容,这里的意思是要将skin目录下的所有文件安装到/usr/local/skin中
data_DATA=skin/* 
#程序打包时要加入的其它文件,使用make dist生成tar.gz文件时会放进去的东西
EXTRA_DIST=skin

src目录下的Makefile.am文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#libxml2 , GTK+2.0和GThread-2.0的cflags和libs
#libxml2安装了xml2-config脚本,GTK+2.0和GThread-2.0安装了.pc pkg-config文件
AM_CPPFLAGS=`xml2-config --cflags` `pkg-config --cflags gtk+-2.0 gthread-2.0`
AM_LDFLAGS=`xml2-config --libs` `pkg-config --libs gtk+-2.0 gthread-2.0`
#预定义的目录,prefix已经说过了
prefix=/usr/local
#这个是可执行文件安装的目录
bindir=$(prefix)/bin
#这个是自定义的目录,用来安装包含协议实现部分的静态库的
slibdir=/usr/lib
#编译生成可执行文件名称
bin_PROGRAMS=openfetion
#这里必须以上一步定义的名称为前缀,编译openfetion所需要的源文件
openfetion_SOURCES=openfetion.cpp  fetion_ui.cpp  ... login_ui.cpp
#编译openfetion所需要的库文件,libfx.a是我事先编译好了的。
openfetion_LDADD=libfx.a
#这个变量前面也说了,要把下面这些文件打包放到tar.gz中
EXTRA_DIST= 	   fetion_ui.h  main_ui.h  .... libfx.a
#要安装的头文件,执行完make install后,这些文件将被安装到/usr/include里面
include_HEADERS=   fgroup.h   flogin.h ... common.h
#自定义目录的数据文件,执行完make install后,这个文件就会被安装到/usr/lib里面
slib_DATA=libfx.a
3.生成GNU风格的项目时需要在顶层目录中你创建NEWS、 README、 ChangeLog 、AUTHOR这几个文件。
touch NEWS README ChangeLog AUTHOR
如果不需要生成GNU风格的项目就不需要创建这几个文件,而是需要在Makefile.am中加入
AUTOMAKE_OPTIONS = foreign
这是执行automake命令时的选项
4.执行aclocal。
由configure.in生成aclocal.m4
5.执行autoconf
由configure.in和aclocal.m4生成configure脚本
6.执行automake
由Makefile.am和configure.in生成各级目录下的Makefile.in
./configure执行的时候会扫描各个目录下的Makefile.in生成不同的Makefile。然后就可以执行make和make install了

GNU Automake工具集的功能远不止这些,我了解地也不够深刻,继续学习。

分类: Linux 标签: , , ,

linux下获取当前程序的绝对路径

二月 25th, {2010 没有评论 15,525 人阅读过  

在linux下运行的程序经常需要获取自己的绝对路径,程序可能需要引用外部的资源文件,比如在../skin/目录下的图片,这样普通程序是没有问题,但当程序在安装到/usr/bin/目录中,或者为程序建立连接以后就会出现问题,我们可以直接通过运行程序的链接来运行程序,这样../skin/目录就找不到了,因为当前目录并不是程序所在的目录,而且链接所在的目录,所以在它的上一级目录中根本找不到skin目录,所以就需要获取程序的绝对路径,用到了一个函数readlink,原型如下:

1
2
3
#include <unistd.h>
 
ssize_t readlink(const char *restrict path , char *restrict buf , size_t bufsize);

该函数的作用是读取符号链接的原路径,将它存到buf中,返回添充到buf中的字节数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <unistd.h>
#include <stdio.h>
 
int main(int argc , char* argv[])
{
	char buf[1024] = { 0 };
	int n;
 
	n = readlink("/bin/mail" , buf , sizeof(buf));
	if( n > 0 && n < sizeof(buf))
	{
		printf("%s\n" , buf);
	}
}

程序运行后输出:/usr/bin/mailx

linux系统中有个符号链接:/proc/self/exe 它代表当前程序,所以可以用readlink读取它的源路径就可以获取当前程序的绝对路径,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <unistd.h>
#include <stdio.h>
 
int main(int argc , char* argv[])
{
	char buf[1024] = { 0 };
	int n;
 
	n = readlink("/proc/self/exe" , buf , sizeof(buf));
	if( n > 0 && n < sizeof(buf))
	{
		printf("%s\n" , buf);
	}
}
1
2
ouclwp@darkstar:~/socket$ ./read 
/home/ouclwp/socket/read

分类: C/C++ 标签: ,

飞信文件传输协议简述

二月 3rd, {2010 没有评论 9,696 人阅读过  

今天切回win分析了一下飞信的一些零散的功能的协议,觉得好不容易切过来就抢包看了看文件传输的协议。状态机我就不细划了,简单的地写一下几个重要的点:
当发起文件传输请求的时候,客户端向服务器发起ShareContent的请求:

fetion.com.cn SIP-C/2.0
F: 916098834
I: 3
Q: 0 O
K: ShareContent
T: sip:572003969@fetion.com.cn;p=4599
L: 460

1
2
3
4
5
6
7
8
9
<share-content id="6b984ea5-2e66-48f4-acb3-60513160162a">
<caps modes="block;relay;p2p;p2pV2;relayV2;p2pV3;scV2" max-size="2097151" />
<client outer-ip="" inner-ip="59.64.128.137:1429;" port="1428" />
<fileinfo>
<transmit type="p2p" session-id="xz4BBcV6b984ea52e6648f4acb360513160162a" />
<file name="Desktop.rar" size="526697" url="" 
md5="1a0edaa0a213be4a28d415594a150053" id="6b984ea5-2e66-48f4-acb3-60513160162a" file-type="unknown" />
</fileinfo>
</share-content>

这里面包含几个重要的字段,session-id,id,md5
md5显而易见是对要传输的文件做md5散列运算得出的字符串,用于在接收端对文件内容的完整性进行校验。
id 其实是Guid,也就是全局唯一标识符,它指在一台机器上生成的数字,在同一时空中不会有另一台机器上的数字与它相同。
官方飞信是能C#开发的,GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。例如:337c7f2b-7a34-4f50-9141-bab9e6478cc8 即为有效的 GUID 值。 查看了一下飞信生成Guid用了一句话:

System.Guid.NewGuid().ToString("D");

session-id的生成是这样的,把id中的‘-’去掉,然后在前面加上”xz4BBcV”这个字符串,C#代码如下:

1
2
3
4
5
6
7
public string SessionId
{
    get
    {
        return ("xz4BBcV" + this.SessionGuid.ToString().Replace("-", string.Empty));
    }
}

filetype字段的定义

1
2
3
4
5
public enum ShareContentFileType
{
    Unknown,
    DirectSendImage
}

接收端接收文件时向服务器发送如下信息:

IN 916098834 SIP-C/2.0
I: 1
Q: 4 IN
F: sip:572003969@fetion.com.cn;p=4599
L: 201

1
2
3
<share-content action="accept">
<file id="c36b9ea6-7704-4860-a323-9470db7fab74" />
<client prefer-types="FFFFFFF" inner-ip="3B408089" net-type="7" udp-inner-port="1497" tcp-port="1496" /></share-content>

id就不用说了,在同一个会话中都使用一个id,prefer-types是指接收端希望使用的传输协议,共有如下几种类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public enum ShareContentType
{
    All = 0xfffffff,
    None = 0,
    P2P = 0xff00,
    RelayAndBlock = 1,
    TCP = 0x100,
    UDP = 0x200,
    V2All = 0xff0000,
    V2HttpRelay = 0x200000,
    V2TcpClient = 0x20000,
    V2TcpRelay = 0x100000,
    V2TcpServer = 0x10000,
    V2Udp = 0x40000
}

在这里使用FFFFFFF表示可以使用所有的类型进行传输,后来分析了一下发现其实飞信文件传输用的一直都是P2P。
OK,这些问题搞清楚了文件传输的实现就是时间的问题了。

分类: Protocol 标签: ,