#!/usr/bin/python policy = None QUEUE_FILE = 'torrent.lst' POLICY_FILE = 'policy.conf' HISTORY_FILE = 'history.lst' IP2CC_FILE = 'ip2cc.db' UNKNOWN_ID_FILE = 'unknownid.log' TORRENT_FORMAT = 'torrent_format' #DEFAULT_TORRENT_FORMAT = 'r3,id:l20,title:r6,progress:r7,dlsize:l7,totalsize:l8,eta:r4,dlspeed:r4,ulspeed:r6,seeds:r6,peers:l10,btstatus:r6,ratio:l,activity' DEFAULT_TORRENT_FORMAT = 'r,id:l20,title:r,progress:r,dlsize:l,totalsize:r,eta:r,dlspeed:r,ulspeed:r,seeds:r,peers:l,btstatus:r,ratio:l,activity' SPEW_FORMAT = 'spew_format' #DEFAULT_SPEW_FORMAT = 'l15,ip:r5,rport:l2,cc:l1,direction:r4,uprate:r4,downrate:r7,dtotal:r7,utotal:r7,completed:l12,client:l12,netname' DEFAULT_SPEW_FORMAT = 'l,ip:r,rport:l,cc:l,direction:r,uprate:r,downrate:r,dtotal:r,utotal:r,completed:l12,client:l12,netname' PEER_FORMAT = 'peer_format' DEFAULT_PEER_FORMAT = 'l,ip:r,rport:l,cc:l,client:l,netname' ALLOC_TYPE = 'alloc_type' ALLOC_RATE = 'alloc_rate' MAX_FILES_OPEN = 'max_files_open' DEFAULT_COMMAND = 'default_command' DEBUG_LEVEL = 'debug_level' REASSIGN_ID = 'reassign_id' USE_LOCAL_POLICY = 'use_local_policy' USE_SINGLE_PORT = 'use_single_port' REQUEST_BACKLOG = 'request_backlog' SNUB_TIME = 'snub_time' SCHEDULING_INTERVAL = 'scheduling_interval' SCRAPE_INTERVAL = 'scrape_interval' REREQUEST_INTERVAL = 'rerequest_interval' IPV6_BINDS_V4 = 'ipv6_binds_v4' UPNP_NAT_ACCESS = 'upnp_nat_access' IDLE_TIMEOUT = 'idle_timeout' IDLE_TIMEOUT_CHECK_INTERVAL = 'idle_timeout_check_interval' PEER_ID = 'peer_id' ENABLE_DHT = 'enable_dht' DEFAULT_ENCODING = 'default_encoding' FILESYSTEM_ENCODING = 'filesystem_encoding' TRACKER_PROXY = 'tracker_proxy' DEFAULT_SOCKET_TIMEOUT = 'default_socket_timeout' MAX_JOB_RUN = 'max_run_job' DEFAULT_PRIORITY = 'default_priority' REPORT_IP = 'report_ip' BIND_IP = 'bind_ip' MIN_FREE_SPACE = 'min_free_space' MIN_PORT = 'min_port' MAX_PORT = 'max_port' RANDOM_PORT = 'random_port' MIN_PEER = 'min_peer' MAX_PEER = 'max_peer' MAX_INITIATE = 'max_initiate' MAX_UPLOAD_RATE = 'max_upload_rate' MAX_DOWNLOAD_RATE = 'max_download_rate' MAX_SEED_RATE = 'max_seed_rate' DEST_PATH = 'dest_path' TORRENT_PATH = 'torrent_path' WRITE_BUFFER_SIZE = 'write_buffer_size' PRIORITIES = 'priorities' MIN_SHARE_RATIO = 'min_share_ratio' MAX_SHARE_RATIO = 'max_share_ratio' MIN_SEED_TIME = 'min_seed_time' MAX_SEED_TIME = 'max_seed_time' MIN_SEEDER = 'min_seeder' MAX_SEEDER = 'max_seeder' MIN_PEER_RATIO = 'min_peer_ratio' MAX_PEER_RATIO = 'max_peer_ratio' LOG_UNKNOWN_ID = 'log_unknown_id' IGNORE_WAITING_MEDIA = 'ignore_waiting_media' ALLOW_ACL = 'allow_acl' DENY_ACL = 'deny_acl' ORDER_ACL = 'order_acl' MAX_LAST_BANNED = 'max_last_banned' MAX_LAST_MESSAGE = 'max_last_message' VERIFY_LINK = 'verify_link' DAEMON_STDOUT = 'daemon_stdout' DAEMON_STDERR = 'daemon_stderr' XMLRPC_ID = 'xmlrpc_id' XMLRPC_IP = 'xmlrpc_ip' XMLRPC_PORT = 'xmlrpc_port' WEBSERVICE_ = 'webservice_' WEBSERVICE_ID = 'webservice_id' WEBSERVICE_IP = 'webservice_ip' WEBSERVICE_PORT = 'webservice_port' WEBSERVICE_CLOSE = 'webservice_close' WEBSERVICE_QUERY = 'webservice_query' WEBSERVICE_ADD = 'webservice_add' WEBSERVICE_DELETE = 'webservice_delete' WEBSERVICE_PAUSE = 'webservice_pause' WEBSERVICE_RESUME = 'webservice_resume' WEBSERVICE_QUEUE = 'webservice_queue' WEBSERVICE_VERSION = 'webservice_version' WEBSERVICE_GSET = 'webservice_gset' import sys,os import math,re import types from ConfigParser import NoOptionError from ip2cc import inet_aton priority_cre = re.compile(r'(?P\[((?P\d+)?(:(?P\d+)?)?)\]:)?(?P-?[012])') def get_policy(root_path=None,**kw): global policy if not policy: import sys if not root_path: root_path = os.path.dirname(os.path.abspath(sys.argv[0])) policy = apply(Policy,(root_path,),kw) return policy def ip_to_int(ip): n = 0 for i in ip.split('.'): n *= 256 n += int(i) & 0xff return n def int_to_ip(n): return '%d.%d.%d.%d' % (n>>24&0xff,n>>16&0xff,n>>8&0xff,n&0xff) def extract_priority(priorities,maxlen): p = ['0']*maxlen index = 0 for item in priorities.split(','): item = item.strip() if not item: continue m = priority_cre.match(item) if not m: continue priority = '0' if m.group('priority'): priority = m.group('priority') if m.group('range'): begin = end = 0 if m.group('begin'): begin = int(m.group('begin')) end = begin+1 if m.group('end'): end = int(m.group('end')) if begin == 0 and end == 0: begin = 0 end = maxlen else: begin = index end = index+1 for i in range(begin,end): p[i] = priority index += 1 return ','.join(p) class AccessControl: def __init__(self,acl): self.update(acl) def update(self,acl): self.acl = acl def exists(self,ip): return self.acl == ip class AllAC(AccessControl): def exists(self,ip): return 1 class NoneAC(AccessControl): def exists(self,ip): return 1 class IPRangeAC(AccessControl): def update(self,acl): try: network,prefix = acl.split('/') self.netmask = ~long(math.pow(2,32-int(prefix))-1) & 4294967295L self.network = ip_to_int(network) except ValueError: try: self.network = ip_to_int(acl) except ValueError: self.network = 0 self.netmask = 4294967295L def exists(self,ip): try: ipn = ip_to_int(ip) except ValueError: return 0 return (ipn & self.netmask) == self.network class NetNameAC(AccessControl): def __init__(self,acl,ipdb=None): AccessControl.__init__(self,acl) self.ipdb = ipdb def update(self,acl): self.acl = acl.upper() def exists(self,ip): try: cc,netname = self.ipdb[ip].split(':') except (KeyError,AssertionError,TypeError,IndexError): return 0 else: return self.acl == netname class CountryAC(AccessControl): def __init__(self,acl,ipdb=None): AccessControl.__init__(self,acl) self.ipdb = ipdb def update(self,acl): self.acl = acl.upper() def exists(self,ip): try: cc,netname = self.ipdb[ip].split(':') except (KeyError,AssertionError): return 0 else: return self.acl == cc class ACL(AccessControl): ip_cre = re.compile(r'\d+\.\d+\.\d+\.\d+(/\d+)?',re.I) def __init__(self,acl,ipdb=None): self.ipdb = ipdb AccessControl.__init__(self,acl) def update(self,acl): self.acls = [] for item in acl.split(','): item = item.strip() if not item: continue if len(item) == 2: o = CountryAC(item,self.ipdb) elif item.upper() == 'ALL': o = AllAC(item) elif item.upper() == 'NONE': o = NoneAC(item) elif self.ip_cre.match(item): o = IPRangeAC(item) else: o = NetNameAC(item,self.ipdb) self.acls.append(o) def exists(self,ip): for o in self.acls: if o.exists(ip): return 1 return 0 class EntryPolicy: def __init__(self,conf=None,section=None): self.params = {MIN_SHARE_RATIO: 1.0, MAX_SHARE_RATIO: 2.0, MIN_SEED_TIME: 0, MAX_SEED_TIME: 86400, MIN_SEEDER: 0, MAX_SEEDER: 4, MIN_PEER_RATIO: 0, MAX_PEER_RATIO: 4, ENABLE_DHT: 1, FILESYSTEM_ENCODING: '', TRACKER_PROXY: '', PRIORITIES: '', USE_LOCAL_POLICY: 0, } pol = get_policy() for key in self.params.keys(): value = pol(key) if value != None: self.params[key] = value if conf and section: self.load(conf,section) def load(self,conf,section): for key in self.params.keys(): try: self.update(key,conf.get(section,key)) except NoOptionError: pass def save(self,conf,section): for key in self.params.keys(): conf.set(section,key,str(self.params[key])) def update(self,key,value): if not self.params.has_key(key): self.params[key] = value return if type(self.params[key]) == type(0): self.params[key] = int(value) elif type(self.params[key]) == type(0.0): self.params[key] = float(value) else: self.params[key] = value def __call__(self,args): return self.get(args) def keys(self): return self.params.keys() def get(self,key): try: ret = self.params[key] except KeyError: ret = get_policy().get(key) return ret class Policy: def __init__(self,root_path,updated=None): self.root_path = root_path self.updated = updated self.share_path = os.path.join(sys.prefix,'share','BTQueue') self.program_path = os.path.dirname(os.path.abspath(sys.argv[0])) self.file = self.get_path(POLICY_FILE) if sys.platform == 'win32' or not os.environ.get('HOME'): default_path = self.program_path else: default_path = os.environ.get('HOME') self.params = {MAX_JOB_RUN: 5, USE_SINGLE_PORT: 1, DEFAULT_COMMAND: 'list running seeding', DEFAULT_SOCKET_TIMEOUT: 60, DEFAULT_PRIORITY: 5, ALLOC_TYPE: 'normal', ALLOC_RATE: 2.0, MAX_FILES_OPEN: 50, TORRENT_FORMAT: DEFAULT_TORRENT_FORMAT, SPEW_FORMAT: DEFAULT_SPEW_FORMAT, PEER_FORMAT: DEFAULT_PEER_FORMAT, SCHEDULING_INTERVAL: 30, SCRAPE_INTERVAL: 20*60, REREQUEST_INTERVAL: 20*60, REQUEST_BACKLOG: 2, IDLE_TIMEOUT: 300, IDLE_TIMEOUT_CHECK_INTERVAL: 60, SNUB_TIME: 30, DEBUG_LEVEL: 0, REASSIGN_ID: 1, LOG_UNKNOWN_ID: 0, REPORT_IP: '', BIND_IP: '', IPV6_BINDS_V4: 0, UPNP_NAT_ACCESS: 1, PEER_ID: 'btq', ENABLE_DHT: 1, DEFAULT_ENCODING: 'tis-620', FILESYSTEM_ENCODING: '', TRACKER_PROXY: '', MIN_PORT: 6881, MAX_PORT: 6999, RANDOM_PORT: 1, MIN_FREE_SPACE: 100*1024*1024, MIN_PEER: 20, MAX_PEER: 90, MAX_INITIATE: 40, MAX_UPLOAD_RATE: 10, MAX_DOWNLOAD_RATE: 20, MAX_SEED_RATE: 10, MIN_SHARE_RATIO: 1.0, MAX_SHARE_RATIO: 2.0, MIN_SEED_TIME: 0, MAX_SEED_TIME: 86400, MIN_SEEDER: 0, MAX_SEEDER: 4, MIN_PEER_RATIO: 0, MAX_PEER_RATIO: 4, DEST_PATH: os.path.join(default_path,'incoming'), TORRENT_PATH: os.path.join(default_path,'torrent'), IGNORE_WAITING_MEDIA: 0, ALLOW_ACL: 'ALL', DENY_ACL: 'NONE', ORDER_ACL: 'allow,deny', MAX_LAST_BANNED: 20, MAX_LAST_MESSAGE: 40, VERIFY_LINK: 0, DAEMON_STDOUT: '', DAEMON_STDERR: '', WRITE_BUFFER_SIZE: 4, XMLRPC_IP: '127.0.0.1', XMLRPC_PORT: 19413, XMLRPC_ID: 'xmlrpcbt', WEBSERVICE_IP: '127.0.0.1', WEBSERVICE_PORT: 19412, WEBSERVICE_ID: 'wsbt', WEBSERVICE_CLOSE: 0, WEBSERVICE_QUERY: 1, WEBSERVICE_ADD: 1, WEBSERVICE_DELETE: 1, WEBSERVICE_PAUSE: 1, WEBSERVICE_RESUME: 1, WEBSERVICE_QUEUE: 1, WEBSERVICE_VERSION: 1, WEBSERVICE_GSET: 0, } self.load() def set_default(self): global policy policy = self def set_handler(self,updated): self.updated = updated def load(self): try: fd = open(self.file,'r') while 1: line = fd.readline() if not line: break if line.strip()[0] == '#': continue try: key,value = line.split('=') except ValueError: continue key = key.strip() value = value.strip() self.update(key,value) fd.close() except IOError: return def save(self): try: fd = open(self.file,'w') keys = self.params.keys() keys.sort() for key in keys: fd.write('%s=%s\n' % (key,str(self.params[key]))) fd.close() except Exception,why: return def update(self,key,value): if not self.params.has_key(key): return if type(self.params[key]) == type(0): if type(value) in types.StringTypes: lv = value.lower() if lv == 'true': value = '1' elif lv == 'false': value = '0' self.params[key] = int(value) elif type(self.params[key]) == type(0.0): self.params[key] = float(value) else: self.params[key] = value if self.updated: self.updated(key) def __call__(self,args): return self.get(args) def keys(self): return self.params.keys() def get(self,key): try: ret = self.params[key] except KeyError: ret = None return ret def get_path(self,basename,writable=0): if not os.path.exists(self.root_path): os.mkdir(self.root_path) for prefix in [self.root_path,self.share_path,self.program_path]: path = os.path.join(prefix,basename) if os.path.exists(path): if writable and \ (not os.access(path,os.W_OK) or prefix != self.root_path): continue return path return os.path.join(self.root_path,basename) def test_acl(): import ip2cc ipdb = ip2cc.CountryByIP('ip2cc.db') acl = IPRangeAC('158.108.0.0/16') print acl.exists('158.108.34.1') print acl.exists('158.109.34.1') acl = NetNameAC('teleglobe-as',ipdb) print acl.exists('203.113.22.1') print acl.exists('158.108.34.1') acl = CountryAC('th',ipdb) print acl.exists('203.113.22.1') print acl.exists('158.108.34.1') acl = ACL('teleglobe-as',ipdb) print acl.exists('203.113.22.1') print acl.exists('158.108.34.1') if __name__ == '__main__': test_acl()