免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2495 | 回复: 0
打印 上一主题 下一主题

CS 1.6 服务器信息读取 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-10-23 10:59 |只看该作者 |倒序浏览
CS 1.6 服务器信息读取




最近在做一个CS约战平台的东西,实现类似 HLSW 读取CS服务器信息的工具。研究了一下CS1.6服务器udp协议的东西。分享一下。
对UDP协议不熟悉,可能有错误的地方请大家指点。
这个是协议的的全文
http://developer.valvesoftware.com/wiki/Server_Queries

协议提供了 5 个请求:

Java代码
  1. 1. * The server responds to 5 queries:   
  2. 2. * A2A_PING   
  3. 3. * Ping the server.   
  4. 4.// ping 服务器   
  5. 5. * A2S_SERVERQUERY_GETCHALLENGE   
  6. 6. * Returns a challenge number for use in the player and rules query.   
  7. 7.//challenge number 应该是用于表示一个用户请求。   
  8. 8. * A2S_INFO   
  9. 9. * Basic information about the server.   
  10. 10.//服务器信息   
  11. 11. * A2S_PLAYER   
  12. 12. * Details about each player on the server.   
  13. 13.//列出服务器所有用户   
  14. 14. * A2S_RULES   
  15. 15. * The rules the server is using.   
  16. 16.//服务器的规则   
  17. 17. * Queries should be sent in UDP packets to the listen port of the server, which is typically port 27015.   
  18. 18.//UDP 的数据包,服务器默认端口是 27015  
  19. * The server responds to 5 queries:
  20. * A2A_PING
  21. * Ping the server.
  22. // ping 服务器
  23. * A2S_SERVERQUERY_GETCHALLENGE
  24. * Returns a challenge number for use in the player and rules query.
  25. //challenge number 应该是用于表示一个用户请求。
  26. * A2S_INFO
  27. * Basic information about the server.
  28. //服务器信息
  29. * A2S_PLAYER
  30. * Details about each player on the server.
  31. //列出服务器所有用户
  32. * A2S_RULES
  33. * The rules the server is using.
  34. //服务器的规则
  35. * Queries should be sent in UDP packets to the listen port of the server, which is typically port 27015.
  36. //UDP 的数据包,服务器默认端口是 27015
复制代码
五个请求的内容是:


Java代码
  1. 1.private static final byte[] A2S_INFO_BYTE =   
  2. 2. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,   
  3. 3.  0x54,//T   
  4. 4.  'S', 'o', 'u', 'r', 'c', 'e', ' ', 'E', 'n', 'g', 'i', 'n', 'e', ' ', 'Q', 'u', 'e', 'r', 'y',   
  5. 5.  0x00};   
  6. 6.  
  7. 7.private static final byte[] A2S_PLAYER_BYTE =   
  8. 8. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,   
  9. 9.  0x55,//U   
  10. 10.  (byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,//四位 0xFF 可能被替换为challenge number   
  11. 11.  0x00};   
  12. 12.  
  13. 13.private static final byte[] A2S_RULES_BYTE =   
  14. 14. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,   
  15. 15.  0x56,//V   
  16. 16.  (byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,//四位 0xFF 可能被替换为challenge number   
  17. 17.  0x00};   
  18. 18.  
  19. 19.private static final byte[] A2S_SERVERQUERY_GETCHALLENGE_BYTE =   
  20. 20. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,   
  21. 21.  0x57,//W   
  22. 22.  0x00};   
  23. 23.      
  24. 24.private static final byte[] A2A_PING_BYTE =   
  25. 25. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,   
  26. 26.  0x69,//i   
  27. 27.  0x00};  
  28. private static final byte[] A2S_INFO_BYTE =
  29. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
  30.   0x54,//T
  31.   'S', 'o', 'u', 'r', 'c', 'e', ' ', 'E', 'n', 'g', 'i', 'n', 'e', ' ', 'Q', 'u', 'e', 'r', 'y',
  32.   0x00};

  33. private static final byte[] A2S_PLAYER_BYTE =
  34. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
  35.   0x55,//U
  36.   (byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,//四位 0xFF 可能被替换为challenge number
  37.   0x00};

  38. private static final byte[] A2S_RULES_BYTE =
  39. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
  40.   0x56,//V
  41.   (byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,//四位 0xFF 可能被替换为challenge number
  42.   0x00};

  43. private static final byte[] A2S_SERVERQUERY_GETCHALLENGE_BYTE =
  44. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
  45.   0x57,//W
  46.   0x00};
  47.        
  48. private static final byte[] A2A_PING_BYTE =
  49. new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
  50.   0x69,//i
  51.   0x00};
复制代码
服务器返回的数据包格式:
数据包除去IP/UDP 头部,最大长度为 1400 bytes。
如果单个数据包传输数据则开始的四个字节是 -1 (0xFF,0xFF,0xFF,0xFF)后面是数据。

如果多个数据包传输数据则开始的四个字节是 -2 (0xFE,0xFF,0xFF,0xFF),后面是四个字节的Request ID(对一次请求返回的多个数据包是相同的且唯一),之后是一个字节的数据包大小和编号,低位的4bit是表示请求返回的包的总数,高位的4bit是表示当前包的编号(从零开始)(协议中说 Source Engine 引擎,会用两个字节来标识,但未发现这种服务器,而且后面有两个字节的 Split Length 也没有发现)。第0个数据包开头有四个字节 (0xFF,0xFF,0xFF,0xFF),其他数据包没有。


Java代码
  1. 1.socket.receive(datapack);   
  2. 2.Frame f = new Frame(HelpUtil.getSubBytes(datapack.getData(), 0, datapack.getLength()));   
  3. 3.if(f.isHasNext()){   
  4. 4.    log.debug("has next!");   
  5. 5.    //if(type == SOURCE_OR_SHIP_SERVERS) throw new UnsupportedOperationException(" do not have implient for source agent! ");   
  6. 6.    byte[][] bts = new byte[f.getDataLength()][];   
  7. 7.    bts[f.getIndex()] = f.getData();   
  8. 8.    for(int i=1; i < bts.length; i++){   
  9. 9.        socket.receive(datapack);   
  10. 10.        Frame next = new Frame(HelpUtil.   
  11. 11.                getSubBytes(datapack.getData(), 0, datapack.getLength()));   
  12. 12.        if(!next.isHasNext() || next.getId() != f.getId()){   
  13. 13.            i--;   
  14. 14.            log.warn("one package frame is discard!");   
  15. 15.            //不应该丢弃包,应该根据第一个字节判断返回的类型。   
  16. 16.            continue;   
  17. 17.        }else{   
  18. 18.            bts[next.getIndex()] = next.getData();   
  19. 19.            if(i >= bts.length ) break;   
  20. 20.        }   
  21. 21.    }   
  22. 22.    ByteArrayOutputStream array = new ByteArrayOutputStream();   
  23. 23.    for(int i=0; i<bts.length; i++){   
  24. 24.        array.write(bts[i]);   
  25. 25.    }  
  26. socket.receive(datapack);
  27. Frame f = new Frame(HelpUtil.getSubBytes(datapack.getData(), 0, datapack.getLength()));
  28. if(f.isHasNext()){
  29.         log.debug("has next!");
  30.         //if(type == SOURCE_OR_SHIP_SERVERS) throw new UnsupportedOperationException(" do not have implient for source agent! ");
  31.         byte[][] bts = new byte[f.getDataLength()][];
  32.         bts[f.getIndex()] = f.getData();
  33.         for(int i=1; i < bts.length; i++){
  34.                 socket.receive(datapack);
  35.                 Frame next = new Frame(HelpUtil.
  36.                                 getSubBytes(datapack.getData(), 0, datapack.getLength()));
  37.                 if(!next.isHasNext() || next.getId() != f.getId()){
  38.                         i--;
  39.                         log.warn("one package frame is discard!");
  40.                         //不应该丢弃包,应该根据第一个字节判断返回的类型。
  41.                         continue;
  42.                 }else{
  43.                         bts[next.getIndex()] = next.getData();
  44.                         if(i >= bts.length ) break;
  45.                 }
  46.         }
  47.         ByteArrayOutputStream array = new ByteArrayOutputStream();
  48.         for(int i=0; i<bts.length; i++){
  49.                 array.write(bts[i]);
  50.         }
复制代码
服务器返回的数据起始的一个字节都是标识位(除去开头的 0xFF,0xFF,0xFF,0xFF),这个是后来才发现的,所以现在的设计上有很大问题。如:ping 第一个字节是 'j',A2S_PLAYER 是 'D' ......

如果服务器返回的数据中是字符串 则是以 UTF-8 编码, 并且以 0x00 做为字符串结尾标识。

•A2A_PING 请求:
用户发现服务器是不是可以连接(或检查服务器类型)。
第一个字节 是  'j'(0x6A)
Goldsource servers 引擎的服务器返回


Java代码
  1. 1.0x6A,0x00  
  2. 0x6A,0x00

  3. Source servers 引擎的服务器返回(这种服务器暂时未发现)


  4. Java代码  
  5. [code]1.0x6A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00  
  6. 0x6A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
复制代码
•A2S_SERVERQUERY_GETCHALLENGE [/code]请求:

第一个字节 是 'A' (0x41)
接下来是 4 个字节的 challenge number 用于 A2S_PLAYER 和 A2S_RULES 这个请求的时候替换请求的后四个字节。
很多服务器不支持该请求。

•A2S_INFO 请求:

区分两种服务器
第一个字节分别是  'I','m'(貌似区分是正版服务器,还是盗版服务器,这个不确定)

m 类型:

Java代码
  1. 1.    int i = 0, t;   
  2. 2.    info.setType(bts[i]);   //m / I   
  3. 3.    t = i + 1;   
  4. 4.if(info.getType() == 'm'){   
  5. 5.    i = HelpUtil.find(bts, t, (byte) 0x00);//ip:port   
  6. 6.    t = i + 1;   
  7. 7.    i = HelpUtil.find(bts, t, (byte) 0x00);//server name   
  8. 8.    if(i >= 0){   
  9. 9.        info.setName(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));   
  10. 10.    }   
  11. 11.    t = i + 1;   
  12. 12.    i = HelpUtil.find(bts, t, (byte) 0x00);//map   
  13. 13.    if(i >= 0){   
  14. 14.        info.setMap(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));   
  15. 15.    }   
  16. 16.    t = i + 1;   
  17. 17.    i = HelpUtil.find(bts, t, (byte) 0x00);//Game Directory   
  18. 18.    t = i + 1;   
  19. 19.    i = HelpUtil.find(bts, t, (byte) 0x00);//Game Description   
  20. 20.    if(i >= 0){   
  21. 21.        info.setDescription(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));   
  22. 22.    }   
  23. 23.    t = i + 1;   
  24. 24.    info.setCurrentPlayers(bts[t]);   
  25. 25.    t += 1;   
  26. 26.    info.setMaxPlayers(bts[t]);   
  27. 27.    t += 1; //version   
  28. 28.    t += 1; //Dedicated   
  29. 29.    t += 1; //OS   
  30. 30.    info.setNeedPassword(bts[t++] != 0);//Password   
  31. 31.    t += 1; //IsMod   
  32. 32.    i = t;   
  33. 33.    if(bts[t] == 0x01){   
  34. 34.        t = i + 1;   
  35. 35.        i = HelpUtil.find(bts, t, (byte) 0x00); //URLInfo   
  36. 36.        t = i + 1;   
  37. 37.        i = HelpUtil.find(bts, t, (byte) 0x00); //URLDL   
  38. 38.        t = i + 1; //Nul   
  39. 39.        t += 4; //ModVersion   
  40. 40.        t += 4; //ModSize   
  41. 41.        t += 1; //SvOnly   
  42. 42.        t += 1; //ClDLL   
  43. 43.    }   
  44. 44.    t += 1; //Secure   
  45. 45.    t += 1;//Number of bots   
  46. 46.    byte end = bts[t];//不应该溢出   
  47. 47.}  
  48.         int i = 0, t;
  49.         info.setType(bts[i]);        //m / I
  50.         t = i + 1;
  51. if(info.getType() == 'm'){
  52.         i = HelpUtil.find(bts, t, (byte) 0x00);//ip:port
  53.         t = i + 1;
  54.         i = HelpUtil.find(bts, t, (byte) 0x00);//server name
  55.         if(i >= 0){
  56.                 info.setName(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));
  57.         }
  58.         t = i + 1;
  59.         i = HelpUtil.find(bts, t, (byte) 0x00);//map
  60.         if(i >= 0){
  61.                 info.setMap(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));
  62.         }
  63.         t = i + 1;
  64.         i = HelpUtil.find(bts, t, (byte) 0x00);//Game Directory
  65.         t = i + 1;
  66.         i = HelpUtil.find(bts, t, (byte) 0x00);//Game Description
  67.         if(i >= 0){
  68.                 info.setDescription(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));
  69.         }
  70.         t = i + 1;
  71.         info.setCurrentPlayers(bts[t]);
  72.         t += 1;
  73.         info.setMaxPlayers(bts[t]);
  74.         t += 1; //version
  75.         t += 1; //Dedicated
  76.         t += 1; //OS
  77.         info.setNeedPassword(bts[t++] != 0);//Password
  78.         t += 1; //IsMod
  79.         i = t;
  80.         if(bts[t] == 0x01){
  81.                 t = i + 1;
  82.                 i = HelpUtil.find(bts, t, (byte) 0x00); //URLInfo
  83.                 t = i + 1;
  84.                 i = HelpUtil.find(bts, t, (byte) 0x00); //URLDL
  85.                 t = i + 1; //Nul
  86.                 t += 4; //ModVersion
  87.                 t += 4; //ModSize
  88.                 t += 1; //SvOnly
  89.                 t += 1; //ClDLL
  90.         }
  91.         t += 1; //Secure
  92.         t += 1;//Number of bots
  93.         byte end = bts[t];//不应该溢出
  94. }
复制代码
对于'I'类型


Java代码
  1. 1.if(info.type == 'I'){   
  2. 2.    int version = bts[t++];//version   
  3. 3.    i = HelpUtil.find(bts, t, (byte) 0x00);//server name   
  4. 4.    if(i >= 0){   
  5. 5.        info.setName(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));   
  6. 6.    }   
  7. 7.    t = i + 1;   
  8. 8.    i = HelpUtil.find(bts, t, (byte) 0x00);//Map   
  9. 9.    if(i >= 0){   
  10. 10.        info.setMap(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));   
  11. 11.    }   
  12. 12.    t = i + 1;   
  13. 13.    i = HelpUtil.find(bts, t, (byte) 0x00);//Map   
  14. 14.    if(i >= 0){//Game Directory   
  15. 15.        //info.setMap(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));   
  16. 16.    }   
  17. 17.    t = i + 1;   
  18. 18.    i = HelpUtil.find(bts, t, (byte) 0x00);//Map   
  19. 19.    if(i >= 0){//Game Description   
  20. 20.        info.setDescription(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));   
  21. 21.    }   
  22. 22.    t = i + 1;   
  23. 23.    HelpUtil.toShort(bts[t++],bts[t++]); //AppID   
  24. 24.    info.setCurrentPlayers(bts[t++]);   
  25. 25.    info.setMaxPlayers(bts[t++]);   
  26. 26.    t++; //Number of bots   
  27. 27.    t++; //Dedicated    byte     'l' for listen, 'd' for dedicated, 'p' for SourceTV   
  28. 28.    t++; //Host operating system. 'l' for Linux, 'w' for Windows   
  29. 29.    t++; //Password   
  30. 30.    t++; //Secure   
  31. 31.      
  32. 32.    //后面的数据不清楚做什么用的  所以忽略掉了。   
  33. 33.}else{   
  34. 34.    throw new RuntimeException("donot support type [" + info.type + "]");   
  35. 35.}  
  36. if(info.type == 'I'){
  37.         int version = bts[t++];//version
  38.         i = HelpUtil.find(bts, t, (byte) 0x00);//server name
  39.         if(i >= 0){
  40.                 info.setName(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));
  41.         }
  42.         t = i + 1;
  43.         i = HelpUtil.find(bts, t, (byte) 0x00);//Map
  44.         if(i >= 0){
  45.                 info.setMap(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));
  46.         }
  47.         t = i + 1;
  48.         i = HelpUtil.find(bts, t, (byte) 0x00);//Map
  49.         if(i >= 0){//Game Directory
  50.                 //info.setMap(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));
  51.         }
  52.         t = i + 1;
  53.         i = HelpUtil.find(bts, t, (byte) 0x00);//Map
  54.         if(i >= 0){//Game Description
  55.                 info.setDescription(new String(HelpUtil.getSubBytes(bts, t, i-t), DEFAULT_CHARSET));
  56.         }
  57.         t = i + 1;
  58.         HelpUtil.toShort(bts[t++],bts[t++]); //AppID
  59.         info.setCurrentPlayers(bts[t++]);
  60.         info.setMaxPlayers(bts[t++]);
  61.         t++; //Number of bots
  62.         t++; //Dedicated        byte         'l' for listen, 'd' for dedicated, 'p' for SourceTV
  63.         t++; //Host operating system. 'l' for Linux, 'w' for Windows
  64.         t++; //Password
  65.         t++; //Secure
  66.        
  67.         //后面的数据不清楚做什么用的  所以忽略掉了。
  68. }else{
  69.         throw new RuntimeException("donot support type [" + info.type + "]");
  70. }
复制代码
•A2S_PLAYER 请求:
玩家的列表,名字,得分,在线时间


Java代码
  1. 1.int t = 0;   
  2. 2.byte type = bts[t++];//type  Should be equal to 'D' (0x44)   
  3. 3.int len = bts[t++];   
  4. 4.for(int i=0; i<len; i++){   
  5. 5.    Player p = new Player();   
  6. 6.    p.setIndex(bts[t++]);//序号   
  7. 7.    int u = HelpUtil.find(bts, t, (byte) 0x00);   
  8. 8.    p.setName(new String(HelpUtil.getSubBytes(bts, t, u - t), DEFAULT_CHARSET));//name   
  9. 9.    t = u + 1;   
  10. 10.    p.setKill(Integer.reverseBytes(HelpUtil.toInt(bts[t++],bts[t++],bts[t++],bts[t++])));   
  11. 11.        //Number of kills this player has   
  12. 12.    p.setConnectedTime(   
  13. 13.        Float.intBitsToFloat(//浮点类型  秒数,不清楚为什么用浮点数   
  14. 14.            Integer.reverseBytes(//比较奇怪为什么是反向的字节   
  15. 15.                HelpUtil.toInt(bts[t++],bts[t++],bts[t++],bts[t++])))); //(x)   
  16. 16.    //The time in seconds this player has been connected   
  17. 17.    list.add(p);   
  18. 18.}  
  19. int t = 0;
  20. byte type = bts[t++];//type  Should be equal to 'D' (0x44)
  21. int len = bts[t++];
  22. for(int i=0; i<len; i++){
  23.         Player p = new Player();
  24.         p.setIndex(bts[t++]);//序号
  25.         int u = HelpUtil.find(bts, t, (byte) 0x00);
  26.         p.setName(new String(HelpUtil.getSubBytes(bts, t, u - t), DEFAULT_CHARSET));//name
  27.         t = u + 1;
  28.         p.setKill(Integer.reverseBytes(HelpUtil.toInt(bts[t++],bts[t++],bts[t++],bts[t++])));
  29.                 //Number of kills this player has
  30.         p.setConnectedTime(
  31.                 Float.intBitsToFloat(//浮点类型  秒数,不清楚为什么用浮点数
  32.                         Integer.reverseBytes(//比较奇怪为什么是反向的字节
  33.                                 HelpUtil.toInt(bts[t++],bts[t++],bts[t++],bts[t++])))); //(x)
  34.         //The time in seconds this player has been connected
  35.         list.add(p);
  36. }
复制代码
•A2S_RULES 请求:
这个结构比较简单 字符串的键值对


Java代码
  1. 1.int t = 0;   
  2. 2.int type = bts[t++];//Should be equal to 'E' (0x45)   
  3. 3.short len = HelpUtil.toShort(bts[t++], bts[t++]);//The number of rules reported in this response   
  4. 4.// top is error!   
  5. 5.for(short i=0; ; i++){   
  6. 6.    int u = HelpUtil.find(bts, t, (byte) 0x00);   
  7. 7.    if(u == -1)  break;   
  8. 8.    String key = new String(HelpUtil.getSubBytes(bts, t, u-t));   
  9. 9.    t = u + 1;   
  10. 10.    u = HelpUtil.find(bts, t, (byte) 0x00);   
  11. 11.    String value = new String(HelpUtil.getSubBytes(bts, t, u-t));   
  12. 12.    t = u + 1;   
  13. 13.    map.put(key, value);   
  14. 14.}  
  15. int t = 0;
  16. int type = bts[t++];//Should be equal to 'E' (0x45)
  17. short len = HelpUtil.toShort(bts[t++], bts[t++]);//The number of rules reported in this response
  18. // top is error!
  19. for(short i=0; ; i++){
  20.         int u = HelpUtil.find(bts, t, (byte) 0x00);
  21.         if(u == -1)  break;
  22.         String key = new String(HelpUtil.getSubBytes(bts, t, u-t));
  23.         t = u + 1;
  24.         u = HelpUtil.find(bts, t, (byte) 0x00);
  25.         String value = new String(HelpUtil.getSubBytes(bts, t, u-t));
  26.         t = u + 1;
  27.         map.put(key, value);
  28. }
复制代码
源码SVN地址:https://lineblog.googlecode.com/svn/trunk/
目录:httpAnalysis/cs/ 下

转载请保留原文地址: [url=转载请保留原文地址: http://lchshu001.iteye.com/blog/1207956 , 谢谢 ]转载请保留原文地址: http://lchshu001.iteye.com/blog/1207956 ,  [/url], 谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP