使用Asterisk接收彩信(三):又一次失败的尝试

上一篇文章发现Asterisk板卡无法接收彩信之后,我就在寻找在不购买新的设备(如GPRS猫等)的情况下能使电脑接收到彩信的方法,毕竟我要做的只是想用彩信在自己架设的微博平台上发个微博而已。

 

重新分析彩信的收发过程,发送彩信的手机首先将彩信内容打包成mime格式,然后通过标准的http协议封装,指定http包的host域为彩信中心,使用post方法,直接将这个Http包发送给彩信网关(通常是10.0.0.172:80),当然彩信网关和彩信中心地址是在手机上用户自己设置的,然后彩信网关根据http包里面的彩信中心的url,查找dns后把这个http包送到彩信中心(这段是我猜的),彩信中心收到后发个短信给目标手机,主要包含一个url(当然还有其它内容),告诉目标手机:你有一条彩信,自己到url这个地方来取。然后目标手机构造一个标准的http请求包,其中Host域填写的是url的host,然后将这个包发送给彩信网关,由彩信网关将http包发送给彩信中心,获取响应后再把数据返回给目标手机,目标手机接到的数据时一个http响应包,包含mime数据,内容几乎和发送手机构造的mime数据一样,但略有不同,比如from字段的值貌似就是数据包走彩信中心或者彩信网关的时候加上去的,刚发送的时候抓包并没有发现from字段。

把tcpdump弄到手机上,然后使用adb shell登录进去抓了几个包,然后再pull出来用wirkshark打开截图如下:

发送:

接收:

 

既然接收端手机根据url直接通过标准http协议请求内容,所以我就想可否使用asterisk板卡接收pdu,然后我通过我的手机当服务器,把彩信内容从mmsc里拉出来,再通过我的手机上传到微博网站。

首先是从pdu中提取url的问题,把一个Pdu使用winhex打开,发现url地址非常明显,以http开头并使用/0结尾,很容易就提取出来。

其次是如何提取url内容的问题。

首先我直接在浏览器里打开,发现找不到地址,然后ping那个主机,也就是11.75.9.6,同时ping不通。这也算是意料之内,处于彩信网关之后的gprs网当然通过internet访问不到。

其次我尝试ping彩信网关,10.0.0.172,发现也ping不通,说明彩信网关只能通过手机的网络访问。

使用手机,进入adb shell,ping网关依然ping不通。然后发现接入点选的是cmnet,换到cmwap发现ip地址变到了10.*.*.*,这时候ping彩信网关能ping通,ping彩信网关后面的host也就是(11.75.9.6)也能ping通。说明彩信只能使用wap网进行发送。

编写程序使用java的http请求类直接请求那个url ,结果什么都没返回,猜测请求的并不是标准的http包。

然后根据wireshark里的包自己构造一个请求包,并在java里使用socket连接彩信网关80端口并发送,的确有结果返回,但返回的是401,即鉴权失败。

为什么会这样?

请求包里没有任何鉴权信息,是个单纯的http请求包而已,为什么mmsc不让我提取信息?

猜测1:当前ip地址和手机号有一个绑定关系,mmsc发现你的ip地址和收信人不对应,就不让你提取。但这个想法有个问题,就是移动互联网你的ip会随时变,这个绑定关系也就随时变,变了之后mmsc根据ip地址鉴权想想就会很麻烦。

猜测2:在进行抓包的时候神秘的发现,即使在wap网下,在短信接收和发送的时候网络要进行切换,从wap还是切换到wap,ip地址有一个改变的过程。也许只有在切换过的ip地址才有权进行彩信内容的提取。如何切换的我把文本复制下来了:

# ifconfig rmnet0
rmnet0: ip 10.58.198.145 mask 255.255.255.252 flags [up broadcast running multicast]
# ifconfig rmnet0
rmnet0: ip 10.58.198.145 mask 255.255.255.252 flags [up broadcast running multicast]
# ifconfig rmnet0
rmnet0: ip 10.58.198.145 mask 255.255.255.252 flags [down broadcast multicast]
# ifconfig rmnet0
rmnet0: ip 10.58.198.145 mask 255.255.255.252 flags [down broadcast multicast]
# ifconfig rmnet0
rmnet0: ip 10.86.10.72 mask 255.255.255.252 flags [up broadcast running multicast]
# ifconfig rmnet0
rmnet0: ip 10.86.10.72 mask 255.255.255.252 flags [up broadcast running multicast]
# ifconfig rmnet0
rmnet0: ip 10.86.10.72 mask 255.255.255.252 flags [up broadcast running multicast]
# ifconfig rmnet0
rmnet0: ip 10.86.10.72 mask 255.255.255.252 flags [up broadcast running multicast]

 

我打开wap网(用wap当网络接入点),然后让同学给我发彩信,我就不断的用ifconfig查看手机网络接口情况。我不懂电信网的东西,从我的角度来说,我只能看到发现我的rmnet0接口的ip发生了变化,接收完彩信之后又变化了回去,所以我就猜测可否是这个变化后的ip地址才能接收彩信呢?

但这个想法我没法验证,因为我不知道这个网络的切换到底是什么,并且也不知道如何显示的控制手机进行这个切换。

 

要写的就是这么多,用另一个手机接收板卡的彩信我暂时没有走通。

最后附上根据pdu提取url和构造http包的java代码,如果有需要的拿去用就行:

package roger.mmsTest.bLL;
import java.io.*;

import java.net.*;


public class MmsTools {
	private static MmsTools single;
	private static String MMSGATEWAY="10.0.0.172";
	public static MmsTools getInstance()
	{
		if(single==null)
		{
			single=new MmsTools();
		}
		return single;
	}
	private MmsTools()
	{
		
	}
		public String getMMSXml(String pdu)
	{
		StringBuffer bf=new StringBuffer();
		try {
			Socket socket=new Socket("10.222.26.7",8080);
			InputStreamReader in= new InputStreamReader(socket.getInputStream());    
			PrintWriter out=new PrintWriter(socket.getOutputStream());    
		    String reqpkt=getMMSReqPkt(pdu);
		   
			out.print(reqpkt);
			out.flush();
			System.out.print(reqpkt);
			System.out.flush();
			
		    while(true)
		    {
		    	int c=in.read();
		    	if(c==-1)
		    	{
		    		break;
		    	}
		    	bf.append((char)c);
		    }
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {	
			e.printStackTrace();
		}
		return bf.toString();
	}
	private String getMMSReqPkt(String pdu)
	{
		StringBuffer bf=new StringBuffer();
		String url=getPDUUrl(pdu);
		System.out.println(url);
		//bf.append("GET http://10.222.26.7:8080/was/bKjDhoPf4dRA HTTP/1.1\r\n");
		bf.append("GET ");
		bf.append(url);
		bf.append(" HTTP/1.1\r\n");
		bf.append("Accept: */*, application/vnd.wap.mms-message, application/vnd.wap.sic\r\n");
		bf.append("x-wap-profile: http://www.htcmms.com.tw/Android/Common/DesireZ/ua-profile.xml\r\n");
		bf.append("Accept-Language: en-GB, en-US\r\n");
		//bf.append("Host: 10.222.26.7:8080\r\n");
		bf.append("Host: ");
		bf.append(getHostFromURL(url));
		bf.append("\r\n");
		bf.append("Connection: Keep-Alive\r\n");	
		bf.append("User-Agent: HTC_DesireZ_A7272/1.0\r\n");
		bf.append("\r\n");
		return bf.toString();
	}
	private String getHostFromURL(String url)
	{
		int start=url.indexOf(":");
		start+=3;
		int end=url.indexOf("/",start);
		return url.substring(start,end);
	}
	private String getPDUUrl(String pdu)
	{
		String pdustr=getPDUString(pdu);
		StringBuffer sb=new StringBuffer();
		boolean start=false;
		for(int i=0;i<=pdustr.length()-1;i++)
		{
			char c=pdustr.charAt(i);
		//	System.out.println(c);
			
			if(c=='h' && i+3<=pdustr.length()-1 && pdustr.charAt(i+1)=='t' && pdustr.charAt(i+2)=='t' && pdustr.charAt(i+3)=='p')
			{
				start=true;
			}
			if(start==true)
			{
				if(c=='\0')
				{
					break;
				}
				else
				{
					sb.append(c);
				}
			}
		}
	  //  int end=pdustr.indexOf("\0", start);
	   // String url=pdustr.substring(start,end);
	   // return url;
		return sb.toString();
	}
	private String getPDUString(String pdu)
	{
		StringBuffer bf=new StringBuffer();
		for(int i=0;i<=pdu.length()-2;i+=2)
		{
			bf.append((char)(getIntegerFrom2Char(pdu.charAt(i),pdu.charAt(i+1))));
		}
		return bf.toString();
	}
	private int getIntegerFrom2Char(char a,char b)
	{
		return Integer.valueOf(String.valueOf(a),16)*16+Integer.valueOf(String.valueOf(b),16);
	}
}


ps:我能吐槽为啥这个系列第二篇阅读量那么高么。。。。

你可能感兴趣的:(socket,网络,String,url,手机,WAP)