ClientIdentifier.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. # The contents of this file are subject to the BitTorrent Open Source License
  2. # Version 1.1 (the License). You may not copy or use this file, in either
  3. # source code or executable form, except in compliance with the License. You
  4. # may obtain a copy of the License at http://www.bittorrent.com/license/.
  5. #
  6. # Software distributed under the License is distributed on an AS IS basis,
  7. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  8. # for the specific language governing rights and limitations under the
  9. # License.
  10. #
  11. # Written by Matt Chisholm
  12. # Client list updated by Ed Savage-Jones - May 28th 2005
  13. import re
  14. v64p = '[\da-zA-Z.-]{3}'
  15. matches = (
  16. ('-AZ(?P<version>\d+)-+.+$' , "Azureus" ),
  17. ('-PC(?P<version>\d+)-+.+$' , "CacheLogic" ),
  18. ('M(?P<version>\d-\d+-\d+)-+.+$' , "BitTorrent" ),
  19. ('BI(?P<version>\d-\d+-\d+)-+.+$' , "BitTorrent Seeder" ),
  20. ('T(?P<version>%s)0?-+.+$'%v64p , "BitTornado" ),
  21. ('-UT(?P<version>[\dA-F]+)-+.+$' , u"\xb5Torrent" ),
  22. ('-TS(?P<version>\d+)-+.+$' , "TorrentStorm" ),
  23. ('exbc(?P<bcver>.+)LORD.+$' , "BitLord" ),
  24. ('exbc(?P<bcver>[^-][^-]+)(?!---).+$', "BitComet" ),
  25. ('-BC0(?P<version>\d+)-.+$' , "BitComet" ),
  26. ('FUTB(?P<bcver>.+).+$' , "BitComet Mod1" ),
  27. ('xUTB(?P<bcver>.+).+$' , "BitComet Mod2" ),
  28. ('A(?P<version>%s)-+.+$'%v64p , "ABC" ),
  29. ('S(?P<version>%s)-+.+$'%v64p , "Shadow's" ),
  30. (chr(0)*12 + 'aa.+$' , "Experimental 3.2.1b2" ),
  31. (chr(0)*12 + '.+$' , "BitTorrent (obsolete)"),
  32. ('-G3.+$' , "G3Torrent" ),
  33. ('-LT(?P<version>[A-Za-z0-9]+)-+.+$' , "libtorrent" ),
  34. ('-lt(?P<version>[A-Za-z0-9]+)-+.+$' , "libtorrent rakshasa"),
  35. ('Mbrst(?P<version>\d-\d-\d).+$' , "burst!" ),
  36. ('eX.+$' , "eXeem" ),
  37. ('\x00\x02BS.+(?P<strver>UDP0|HTTPBT)$', "BitSpirit v2" ),
  38. ('\x00[\x02|\x00]BS.+$' , "BitSpirit v2" ),
  39. ('.*(?P<strver>UDP0|HTTPBT)$' , "BitSpirit" ),
  40. ('-BOWP?(?P<version>[\dA-F]+)-.+$', "Bits on Wheels" ),
  41. ('(?P<rsver>.+)RSAnonymous.+$' , "Rufus Anonymous" ),
  42. ('(?P<rsver>.+)RS.+$' , "Rufus" ),
  43. ('-ML(?P<version>(\d\.)+\d)(?:\.(?P<strver>CVS))?-+.+$',"MLDonkey"),
  44. ('346------.+$' , "TorrentTopia 1.70" ),
  45. ('OP(?P<strver>\d{4}).+$' , "Opera" ),
  46. ('-KT(?P<version>\d+)(?P<rc>R\d+)-+.+$', "KTorrent" ),
  47. ('-KT(?P<version>\d+)-+.+$' , "KTorrent" ),
  48. # Unknown but seen in peer lists:
  49. ('-S(?P<version>10059)-+.+$' , "S (unknown)" ),
  50. ('-TR(?P<version>\d+)-+.+$' , "transmission" ),
  51. ('S\x05\x07\x06\x00{7}.+' , "S 576 (unknown)" ),
  52. # Clients I've never actually seen in a peer list:
  53. ('exbc..---.+$' , "BitVampire 1.3.1" ),
  54. ('-BB(?P<version>\d+)-+.+$' , "BitBuddy" ),
  55. ('-CT(?P<version>\d+)-+.+$' , "CTorrent" ),
  56. ('-MT(?P<version>\d+)-+.+$' , "MoonlightTorrent" ),
  57. ('-BX(?P<version>\d+)-+.+$' , "BitTorrent X" ),
  58. ('-TN(?P<version>\d+)-+.+$' , "TorrentDotNET" ),
  59. ('-SS(?P<version>\d+)-+.+$' , "SwarmScope" ),
  60. ('-XT(?P<version>\d+)-+.+$' , "XanTorrent" ),
  61. ('U(?P<version>\d+)-+.+$' , "UPnP NAT Bit Torrent" ),
  62. ('-AR(?P<version>\d+)-+.+$' , "Arctic" ),
  63. ('(?P<rsver>.+)BM.+$' , "BitMagnet" ),
  64. ('BG(?P<version>\d+).+$' , "BTGetit" ),
  65. ('-eX(?P<version>[\dA-Fa-f]+)-.+$',"eXeem beta" ),
  66. ('Plus12(?P<rc>[\dR]+)-.+$' , "Plus! II" ),
  67. ('XBT(?P<version>\d+)[d-]-.+$' , "XBT" ),
  68. ('-ZT(?P<version>\d+)-+.+$' , "ZipTorrent" ),
  69. ('-BitE\?(?P<version>\d+)-.+$' , "BitEruct" ),
  70. ('O(?P<version>%s)-+.+$'%v64p , "Osprey Permaseed" ),
  71. # Guesses based on Rufus source code, never seen in the wild:
  72. ('-BS(?P<version>\d+)-+.+$' , "BTSlave" ),
  73. ('-SB(?P<version>\d+)-+.+$' , "SwiftBit" ),
  74. ('-SN(?P<version>\d+)-+.+$' , "ShareNET" ),
  75. ('-bk(?P<version>\d+)-+.+$' , "BitKitten" ),
  76. ('-SZ(?P<version>\d+)-+.+$' , "Shareaza" ),
  77. ('-MP(?P<version>\d+)-+.+$' , "MooPolice" ),
  78. ('Deadman Walking-.+$' , "Deadman" ),
  79. ('270------.+$' , "GreedBT 2.7.0" ),
  80. ('XTORR302.+$' , "TorrenTres 0.0.2" ),
  81. ('turbobt(?P<version>\d\.\d).+$' , "TurboBT" ),
  82. ('DansClient.+$' , "XanTorrent" ),
  83. ('-PO(?P<version>\d+)-+.+$' , "PO (unknown)" ),
  84. ('-UR(?P<version>\d+)-+.+$' , "UR (unknown)" ),
  85. # Patterns that should be executed last
  86. ('.*Azureus.*' , "Azureus 2.0.3.2" ),
  87. )
  88. matches = [(re.compile(pattern, re.DOTALL), name) for pattern, name in matches]
  89. unknown_clients = {}
  90. def identify_client(peerid, log=None):
  91. #client = 'unknown'
  92. client = repr(peerid)
  93. client_str = str(peerid)
  94. if client_str == client[1:-1]:
  95. client = client_str
  96. version = ''
  97. for pat, name in matches:
  98. m = pat.match(peerid)
  99. if m:
  100. client = name
  101. d = m.groupdict()
  102. if d.has_key('version'):
  103. version = d['version']
  104. version = version.replace('-','.')
  105. if version.find('.') >= 0:
  106. #version = ''.join(version.split('.'))
  107. version = version.split('.')
  108. version = list(version)
  109. for i,c in enumerate(version):
  110. if '0' <= c <= '9':
  111. version[i] = c
  112. elif 'A' <= c <= 'Z':
  113. version[i] = str(ord(c) - 55)
  114. elif 'a' <= c <= 'z':
  115. version[i] = str(ord(c) - 61)
  116. elif c == '.':
  117. version[i] = '62'
  118. elif c == '-':
  119. version[i] = '63'
  120. else:
  121. break
  122. version = '.'.join(version)
  123. elif d.has_key('bcver'):
  124. bcver = d['bcver']
  125. version += str(ord(bcver[0])) + '.'
  126. if len(bcver) > 1:
  127. version += str(ord(bcver[1])/10)
  128. version += str(ord(bcver[1])%10)
  129. elif d.has_key('rsver'):
  130. rsver = d['rsver']
  131. version += str(ord(rsver[0])) + '.'
  132. if len(rsver) > 1:
  133. version += str(ord(rsver[1])/10) + '.'
  134. version += str(ord(rsver[1])%10)
  135. if d.has_key('strver'):
  136. if d['strver'] is not None:
  137. version += d['strver']
  138. if d.has_key('rc'):
  139. rc = 'RC ' + d['rc'][1:]
  140. if version:
  141. version += ' '
  142. version += rc
  143. break
  144. if client == 'unknown':
  145. # identify Shareaza 2.0 - 2.1
  146. if len(peerid) == 20 and chr(0) not in peerid[:15]:
  147. for i in range(16,20):
  148. if ord(peerid[i]) != (ord(peerid[i - 16]) ^ ord(peerid[31 - i])):
  149. break
  150. else:
  151. client = "Shareaza"
  152. if log is not None and 'unknown' in client:
  153. if not unknown_clients.has_key(peerid):
  154. unknown_clients[peerid] = True
  155. log.write('%s\n'%peerid)
  156. log.write('------------------------------\n')
  157. return client, version
  158. if __name__ == '__main__':
  159. import sys
  160. for v in sys.argv[1:]:
  161. print identify_client(v)