Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
at main 148 lines 5.6 kB view raw
1import time 2import urllib.request 3import struct 4import socket 5 6import lib.bencode_open as bencode_open 7from lib.subtl.subtl import UdpTrackerClient 8import socks 9import sockshandler 10import gevent 11 12from Plugin import PluginManager 13from Config import config 14from Debug import Debug 15from util import helper 16 17 18# We can only import plugin host clases after the plugins are loaded 19@PluginManager.afterLoad 20def importHostClasses(): 21 global Peer, AnnounceError 22 from Peer import Peer 23 from Site.SiteAnnouncer import AnnounceError 24 25 26@PluginManager.registerTo("SiteAnnouncer") 27class SiteAnnouncerPlugin(object): 28 def getSupportedTrackers(self): 29 trackers = super(SiteAnnouncerPlugin, self).getSupportedTrackers() 30 if config.disable_udp or config.trackers_proxy != "disable": 31 trackers = [tracker for tracker in trackers if not tracker.startswith("udp://")] 32 33 return trackers 34 35 def getTrackerHandler(self, protocol): 36 if protocol == "udp": 37 handler = self.announceTrackerUdp 38 elif protocol == "http": 39 handler = self.announceTrackerHttp 40 elif protocol == "https": 41 handler = self.announceTrackerHttps 42 else: 43 handler = super(SiteAnnouncerPlugin, self).getTrackerHandler(protocol) 44 return handler 45 46 def announceTrackerUdp(self, tracker_address, mode="start", num_want=10): 47 s = time.time() 48 if config.disable_udp: 49 raise AnnounceError("Udp disabled by config") 50 if config.trackers_proxy != "disable": 51 raise AnnounceError("Udp trackers not available with proxies") 52 53 ip, port = tracker_address.split("/")[0].split(":") 54 tracker = UdpTrackerClient(ip, int(port)) 55 if helper.getIpType(ip) in self.getOpenedServiceTypes(): 56 tracker.peer_port = self.fileserver_port 57 else: 58 tracker.peer_port = 0 59 tracker.connect() 60 if not tracker.poll_once(): 61 raise AnnounceError("Could not connect") 62 tracker.announce(info_hash=self.site.address_sha1, num_want=num_want, left=431102370) 63 back = tracker.poll_once() 64 if not back: 65 raise AnnounceError("No response after %.0fs" % (time.time() - s)) 66 elif type(back) is dict and "response" in back: 67 peers = back["response"]["peers"] 68 else: 69 raise AnnounceError("Invalid response: %r" % back) 70 71 return peers 72 73 def httpRequest(self, url): 74 headers = { 75 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11', 76 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 77 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 78 'Accept-Encoding': 'none', 79 'Accept-Language': 'en-US,en;q=0.8', 80 'Connection': 'keep-alive' 81 } 82 83 req = urllib.request.Request(url, headers=headers) 84 85 if config.trackers_proxy == "tor": 86 tor_manager = self.site.connection_server.tor_manager 87 handler = sockshandler.SocksiPyHandler(socks.SOCKS5, tor_manager.proxy_ip, tor_manager.proxy_port) 88 opener = urllib.request.build_opener(handler) 89 return opener.open(req, timeout=50) 90 elif config.trackers_proxy == "disable": 91 return urllib.request.urlopen(req, timeout=25) 92 else: 93 proxy_ip, proxy_port = config.trackers_proxy.split(":") 94 handler = sockshandler.SocksiPyHandler(socks.SOCKS5, proxy_ip, int(proxy_port)) 95 opener = urllib.request.build_opener(handler) 96 return opener.open(req, timeout=50) 97 98 def announceTrackerHttps(self, *args, **kwargs): 99 kwargs["protocol"] = "https" 100 return self.announceTrackerHttp(*args, **kwargs) 101 102 def announceTrackerHttp(self, tracker_address, mode="start", num_want=10, protocol="http"): 103 tracker_ip, tracker_port = tracker_address.rsplit(":", 1) 104 if helper.getIpType(tracker_ip) in self.getOpenedServiceTypes(): 105 port = self.fileserver_port 106 else: 107 port = 1 108 params = { 109 'info_hash': self.site.address_sha1, 110 'peer_id': self.peer_id, 'port': port, 111 'uploaded': 0, 'downloaded': 0, 'left': 431102370, 'compact': 1, 'numwant': num_want, 112 'event': 'started' 113 } 114 115 url = protocol + "://" + tracker_address + "?" + urllib.parse.urlencode(params) 116 117 s = time.time() 118 response = None 119 # Load url 120 if config.tor == "always" or config.trackers_proxy != "disable": 121 timeout = 60 122 else: 123 timeout = 30 124 125 with gevent.Timeout(timeout, False): # Make sure of timeout 126 req = self.httpRequest(url) 127 response = req.read() 128 req.close() 129 req = None 130 131 if not response: 132 raise AnnounceError("No response after %.0fs" % (time.time() - s)) 133 134 # Decode peers 135 try: 136 peer_data = bencode_open.loads(response)[b"peers"] 137 response = None 138 peer_count = int(len(peer_data) / 6) 139 peers = [] 140 for peer_offset in range(peer_count): 141 off = 6 * peer_offset 142 peer = peer_data[off:off + 6] 143 addr, port = struct.unpack('!LH', peer) 144 peers.append({"addr": socket.inet_ntoa(struct.pack('!L', addr)), "port": port}) 145 except Exception as err: 146 raise AnnounceError("Invalid response: %r (%s)" % (response, Debug.formatException(err))) 147 148 return peers