예제 #1
0
파일: tcprelay.py 프로젝트: able8/ss
 def handle_event(self, sock, event):
     logging.debug("Running in the TCPRelayHandler class. [handle_event]")
     # handle all events in this handler and dispatch them to methods
     if self._stage == STAGE_DESTROYED:
         logging.debug('ignore handle_event: destroyed')
         return
     # order is important
     if sock == self._remote_sock:
         if event & eventloop.POLL_ERR:
             self._on_remote_error()
             if self._stage == STAGE_DESTROYED:
                 return
         if event & (eventloop.POLL_IN | eventloop.POLL_HUP):
             self._on_remote_read()
             if self._stage == STAGE_DESTROYED:
                 return
         if event & eventloop.POLL_OUT:
             self._on_remote_write()
     elif sock == self._local_sock:
         if event & eventloop.POLL_ERR:
             self._on_local_error()
             if self._stage == STAGE_DESTROYED:
                 return
         if event & (eventloop.POLL_IN | eventloop.POLL_HUP):
             self._on_local_read()
             if self._stage == STAGE_DESTROYED:
                 return
         if event & eventloop.POLL_OUT:
             self._on_local_write()
     else:
         logging.warn('unknown socket')
         common.error_to_file('unknown socket',self._config)
예제 #2
0
 def handle_event(self, sock, fd, event):
     if sock == self._control_socket and event == eventloop.POLL_IN:
         data, self._control_client_addr = sock.recvfrom(BUF_SIZE)
         parsed = self._parse_command(data)
         if parsed:
             command, config = parsed
             a_config = self._config.copy()
             if config:
                 a_config.update(config)
             if 'server_port' not in a_config:
                 logging.error('can not find server_port in config',
                               self._config)
                 common.error_to_file('can not find server_port in config',
                                      self._config)
             else:
                 if command == 'add':
                     self.add_port(a_config)
                 elif command == 'remove':
                     self.remove_port(a_config)
                 elif command == 'ping':
                     self._send_control_data(b'pong')
                 else:
                     logging.error('unknown command %s' % command)
                     common.error_to_file('unknown command %s' % command,
                                          self._config)
예제 #3
0
 def handle_event(self, sock, fd, event):
     if sock == self._server_socket:
         if event & eventloop.POLL_ERR:
             logging.error('UDP server_socket err')
             common.error_to_file('UDP server_socket err', self._config)
         self._handle_server()
     elif sock and (fd in self._sockets):
         if event & eventloop.POLL_ERR:
             logging.error('UDP client_socket err')
             common.error_to_file('UDP client_socket err', self._config)
             if not self._is_local:
                 if self._config.has_key('port_limit') and self._config[
                         'port_limit'] != "" and os.path.exists(
                             self._config['port_limit']):
                     port_limits = json.loads(
                         open(self._config['port_limit']).read())
                     if str(self._listen_port
                            ) in port_limits and port_limits[
                                '%s' %
                                self._listen_port]['used'] >= port_limits[
                                    '%s' % self._listen_port]['total']:
                         logging.warn(
                             '[UDP] server listen port [%s] used traffic is over the setting value'
                             % self._listen_port)
                         self.close()
         self._handle_client(sock)
예제 #4
0
 def _write_to_sock(self, data, sock):
     logging.debug("Running in the TCPRelayHandler class. [_write_to_sock]")
     # write data to sock
     # if only some of the data are written, put remaining in the buffer
     # and update the stream to wait for writing
     if not data or not sock:
         return False
     uncomplete = False
     try:
         l = len(data)
         if sock == self._local_sock and self._is_local and self._stage == STAGE_INIT:
             logging.info("[Client] Received data from browser and just sending 'hello' back to [browser] ! data length is: [%s]" % l)
         elif sock == self._remote_sock and self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Client] Received data from browser and just sending -encrypted- data to [VPS] ! data length is: [%s]" % l)
         elif sock == self._local_sock and self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Client] Received data from VPS and just sending -decrypted- data to [browser] ! data length is: [%s]" % l)
         elif sock == self._remote_sock and not self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Server] Received data from client and going to send -decrypted- data to [INTERNET] ! data length is: [%s]" % l)
         elif sock == self._local_sock and not self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Server] Received data from INTERNET and going to send -encrypted- data to [client] ! data length is: [%s]" % l)
             if self._config.has_key("limit"):
                 if self._config['limit'].has_key(str(self._server._listen_port)):
                     self._config['limit'][str(self._server._listen_port)]['used'] += l
             #if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
             #   port_limits = json.loads(open(self._config['port_limit']).read())
             #   if str(self._server._listen_port) in port_limits:
             #       port_limits['%s' % self._server._listen_port]['used'] = port_limits['%s' % self._server._listen_port]['used'] + l
             #       open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True))
         s = sock.send(data)
         if s < l:
             data = data[s:]
             uncomplete = True
     except (OSError, IOError) as e:
         error_no = eventloop.errno_from_exception(e)
         if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK):
             uncomplete = True
         else:
             shell.print_exception(e)
             self.destroy()
             return False
     if uncomplete:
         if sock == self._local_sock:
             self._data_to_write_to_local.append(data)
             self._update_stream(STREAM_DOWN, WAIT_STATUS_WRITING)
         elif sock == self._remote_sock:
             self._data_to_write_to_remote.append(data)
             self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
         else:
             logging.error('write_all_to_sock:unknown socket')
             common.error_to_file('write_all_to_sock:unknown socket',self._config)
     else:
         if sock == self._local_sock:
             self._update_stream(STREAM_DOWN, WAIT_STATUS_READING)
         elif sock == self._remote_sock:
             self._update_stream(STREAM_UP, WAIT_STATUS_READING)
         else:
             logging.error('write_all_to_sock:unknown socket')
             common.error_to_file('write_all_to_sock:unknown socket',self._config)
     return True
예제 #5
0
파일: tcprelay.py 프로젝트: able8/ss
 def _on_remote_error(self):
     logging.debug("Running in the TCPRelayHandler class. [_on_remote_error]")
     logging.warn('got remote error')
     common.error_to_file('got remote error',self._config)
     if self._remote_sock:
         logging.error(eventloop.get_sock_error(self._remote_sock))
         common.error_to_file(eventloop.get_sock_error(self._remote_sock),self._config)
     self.destroy()
예제 #6
0
 def _write_to_sock(self, data, sock):
     logging.debug("Running in the TCPRelayHandler class. [_write_to_sock]")
     # write data to sock
     # if only some of the data are written, put remaining in the buffer
     # and update the stream to wait for writing
     if not data or not sock:
         return False
     uncomplete = False
     try:
         l = len(data)
         if sock == self._local_sock and self._is_local and self._stage == STAGE_INIT:
             logging.info("[Client] Received data from browser and just sending 'hello' back to [browser] ! data length is: [%s]" % l)
         elif sock == self._remote_sock and self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Client] Received data from browser and just sending -encrypted- data to [VPS] ! data length is: [%s]" % l)
         elif sock == self._local_sock and self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Client] Received data from VPS and just sending -decrypted- data to [browser] ! data length is: [%s]" % l)
         elif sock == self._remote_sock and not self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Server] Received data from client and going to send -decrypted- data to [INTERNET] ! data length is: [%s]" % l)
         elif sock == self._local_sock and not self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Server] Received data from INTERNET and going to send -encrypted- data to [client] ! data length is: [%s]" % l)
         if not self._is_local:
             if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
                 port_limits = json.loads(open(self._config['port_limit']).read())
                 if str(self._server._listen_port) in port_limits:
                     port_limits['%s' % self._server._listen_port]['used'] = port_limits['%s' % self._server._listen_port]['used'] + len(data)
                     open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True))
         s = sock.send(data)
         if s < l:
             data = data[s:]
             uncomplete = True
     except (OSError, IOError) as e:
         error_no = eventloop.errno_from_exception(e)
         if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK):
             uncomplete = True
         else:
             shell.print_exception(e)
             self.destroy()
             return False
     if uncomplete:
         if sock == self._local_sock:
             self._data_to_write_to_local.append(data)
             self._update_stream(STREAM_DOWN, WAIT_STATUS_WRITING)
         elif sock == self._remote_sock:
             self._data_to_write_to_remote.append(data)
             self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
         else:
             logging.error('write_all_to_sock:unknown socket')
             common.error_to_file('write_all_to_sock:unknown socket',self._config)
     else:
         if sock == self._local_sock:
             self._update_stream(STREAM_DOWN, WAIT_STATUS_READING)
         elif sock == self._remote_sock:
             self._update_stream(STREAM_UP, WAIT_STATUS_READING)
         else:
             logging.error('write_all_to_sock:unknown socket')
             common.error_to_file('write_all_to_sock:unknown socket',self._config)
     return True
예제 #7
0
 def remove_port(self, config):
     port = int(config['server_port'])
     servers = self._relays.get(port, None)
     if servers:
         logging.info("removing server at %s:%d" % (config['server'], port))
         t, u = servers
         t.close(next_tick=False)
         u.close(next_tick=False)
         del self._relays[port]
     else:
         logging.error("server not exist at %s:%d" %
                       (config['server'], port))
         common.error_to_file(
             "server not exist at %s:%d" % (config['server'], port),
             self._config)
예제 #8
0
 def _parse_command(self, data):
     # commands:
     # add: {"server_port": 8000, "password": "******"}
     # remove: {"server_port": 8000"}
     data = common.to_str(data)
     parts = data.split(':', 1)
     if len(parts) < 2:
         return data, None
     command, config_json = parts
     try:
         config = json.loads(config_json)
         return command, config
     except Exception as e:
         logging.error(e)
         common.error_to_file('%s' % str(e), self._config)
         return None
예제 #9
0
    def __init__(self, config, dns_resolver, is_local, stat_callback=None):
        logging.debug("Running in the TCPRelay class. [init]")
        self._config = config
        self._config_file = "config.json"
        self._is_local = is_local
        self._dns_resolver = dns_resolver
        self._closed = False
        self._eventloop = None
        self._fd_to_handlers = {}
        self._check_need_save_config_timestamp = "check_point"

        self._timeout = config['timeout']
        self._timeouts = []  # a list for all the handlers
        # we trim the timeouts once a while
        self._timeout_offset = 0  # last checked position for timeout
        self._handler_to_timeouts = {}  # key: handler value: index in timeouts
        self._config_tmp = {}

        if is_local:
            listen_addr = config['local_address']
            listen_port = config['local_port']
        else:
            listen_addr = config['server']
            listen_port = config['server_port']
        self._listen_port = listen_port

        addrs = socket.getaddrinfo(
            listen_addr, listen_port, 0, socket.SOCK_STREAM, socket.SOL_TCP)
        if len(addrs) == 0:
            raise Exception("can't get addrinfo for %s:%d" %
                            (listen_addr, listen_port))
        af, socktype, proto, canonname, sa = addrs[0]
        server_socket = socket.socket(af, socktype, proto)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind(sa)
        server_socket.setblocking(False)
        if config['fast_open']:
            try:
                server_socket.setsockopt(socket.SOL_TCP, 23, 5)
            except socket.error:
                logging.error('warning: fast open is not available')
                common.error_to_file('warning: fast open is not available',self._config)

                self._config['fast_open'] = False
        server_socket.listen(1024)
        self._server_socket = server_socket
        self._stat_callback = stat_callback
예제 #10
0
 def handle_event(self, sock, fd, event):
     if sock == self._server_socket:
         if event & eventloop.POLL_ERR:
             logging.error('UDP server_socket err')
             common.error_to_file('UDP server_socket err',self._config)
         self._handle_server()
     elif sock and (fd in self._sockets):
         if event & eventloop.POLL_ERR:
             logging.error('UDP client_socket err')
             common.error_to_file('UDP client_socket err',self._config)
             if not self._is_local:
                 if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
                     port_limits = json.loads(open(self._config['port_limit']).read())
                     if str(self._listen_port) in port_limits and port_limits['%s' % self._listen_port]['used'] >= port_limits['%s' % self._listen_port]['total']:
                         logging.warn('[UDP] server listen port [%s] used traffic is over the setting value' % self._listen_port)
                         self.close()
         self._handle_client(sock)
예제 #11
0
 def handle_event(self, sock, fd, event):
     logging.debug("Running in the TCPRelay class....[_handle_events]")
     if not self._is_local:
         if self._config.has_key("limit"):
             if self._config['limit'].has_key(str(self._listen_port)):
                 if int(self._config['limit'][str(self._listen_port)]['total']) > 0:
                     if self._config['limit'][str(self._listen_port)]['used'] >= self._config['limit'][str(self._listen_port)]['total']:
                         logging.error('[TCP] server listen port [%s] used traffic is over the setting value' % self._listen_port)
                         self.close()
         #if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
         #   port_limits = json.loads(open(self._config['port_limit']).read())
         #   if str(self._listen_port) in port_limits and port_limits['%s' % self._listen_port]['used'] >= port_limits['%s' % self._listen_port]['total']:
         #       logging.warn('[TCP] server listen port [%s] used traffic is over the setting value' % self._listen_port)
         #       self.close()
     # handle events and dispatch to handlers
     if sock:
         logging.debug("LOGGING fd %d %s" %
                       (fd, eventloop.EVENT_NAMES.get(event, event)))
     if sock == self._server_socket:
         if event & eventloop.POLL_ERR:
             # TODO
             raise Exception('server_socket error')
             common.error_to_file("server_socket error",self._config)
         try:
             logging.debug('accept')
             conn = self._server_socket.accept()
             TCPRelayHandler(self, self._fd_to_handlers,
                             self._eventloop, conn[0], self._config,
                             self._dns_resolver, self._is_local)
         except (OSError, IOError) as e:
             error_no = eventloop.errno_from_exception(e)
             if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                             errno.EWOULDBLOCK):
                 return
             else:
                 shell.print_exception(e)
                 if self._config['verbose']:
                     traceback.print_exc()
     else:
         if sock:
             handler = self._fd_to_handlers.get(fd, None)
             if handler:
                 handler.handle_event(sock, event)
         else:
             logging.warn('poll removed fd')
             common.error_to_file('poll removed fd',self._config)
예제 #12
0
 def add_port(self, config):
     port = int(config['server_port'])
     servers = self._relays.get(port, None)
     if servers:
         logging.error("server already exists at %s:%d" %
                       (config['server'], port))
         common.error_to_file(
             "server already exists at %s:%d" % (config['server'], port),
             self._config)
         return
     logging.info("adding server at %s:%d" % (config['server'], port))
     t = tcprelay.TCPRelay(config, self._dns_resolver, False,
                           self.stat_callback)
     u = udprelay.UDPRelay(config, self._dns_resolver, False,
                           self.stat_callback)
     t.add_to_loop(self._loop)
     u.add_to_loop(self._loop)
     self._relays[port] = (t, u)
예제 #13
0
    def __init__(self, config, dns_resolver, is_local, stat_callback=None):
        logging.debug("Running in the TCPRelay class. [init]")
        self._config = config
        self._is_local = is_local
        self._dns_resolver = dns_resolver
        self._closed = False
        self._eventloop = None
        self._fd_to_handlers = {}

        self._timeout = config['timeout']
        self._timeouts = []  # a list for all the handlers
        # we trim the timeouts once a while
        self._timeout_offset = 0  # last checked position for timeout
        self._handler_to_timeouts = {}  # key: handler value: index in timeouts

        if is_local:
            listen_addr = config['local_address']
            listen_port = config['local_port']
        else:
            listen_addr = config['server']
            listen_port = config['server_port']
        self._listen_port = listen_port

        addrs = socket.getaddrinfo(
            listen_addr, listen_port, 0, socket.SOCK_STREAM, socket.SOL_TCP)
        if len(addrs) == 0:
            raise Exception("can't get addrinfo for %s:%d" %
                            (listen_addr, listen_port))
        af, socktype, proto, canonname, sa = addrs[0]
        server_socket = socket.socket(af, socktype, proto)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind(sa)
        server_socket.setblocking(False)
        if config['fast_open']:
            try:
                server_socket.setsockopt(socket.SOL_TCP, 23, 5)
            except socket.error:
                logging.error('warning: fast open is not available')
                common.error_to_file('warning: fast open is not available',self._config)

                self._config['fast_open'] = False
        server_socket.listen(1024)
        self._server_socket = server_socket
        self._stat_callback = stat_callback
예제 #14
0
	def handle_event(self, sock, fd, event):
		if sock != self._sock:
			return
		if event & eventloop.POLL_ERR:
			logging.error('dns socket err')
			common.error_to_file('dns socket err',self._config)
			self._loop.remove(self._sock, self)
			self._sock.close()
			# TODO when dns server is IPv6
			self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
									   socket.SOL_UDP)
			self._sock.setblocking(False)
			self._loop.add(self._sock, eventloop.POLL_IN, self)
		else:
			data, addr = sock.recvfrom(1024)
			if addr[0] not in self._servers:
				logging.warn('received a packet other than our dns')
				common.error_to_file('received a packet other than our dns',self._config)
				return
			self._handle_data(data)
예제 #15
0
 def handle_event(self, sock, fd, event):
     if sock != self._sock:
         return
     if event & eventloop.POLL_ERR:
         logging.error('dns socket err')
         common.error_to_file('dns socket err', self._config)
         self._loop.remove(self._sock, self)
         self._sock.close()
         # TODO when dns server is IPv6
         self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
                                    socket.SOL_UDP)
         self._sock.setblocking(False)
         self._loop.add(self._sock, eventloop.POLL_IN, self)
     else:
         data, addr = sock.recvfrom(1024)
         if addr[0] not in self._servers:
             logging.warn('received a packet other than our dns')
             common.error_to_file('received a packet other than our dns',
                                  self._config)
             return
         self._handle_data(data)
예제 #16
0
 def handle_event(self, sock, fd, event):
     logging.debug("Running in the TCPRelay class....[_handle_events]")
     # handle events and dispatch to handlers
     if sock:
         logging.debug("LOGGING fd %d %s" %
                       (fd, eventloop.EVENT_NAMES.get(event, event)))
     if not self._is_local:
         if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
             port_limits = json.loads(open(self._config['port_limit']).read())
             if str(self._listen_port) in port_limits and port_limits['%s' % self._listen_port]['used'] >= port_limits['%s' % self._listen_port]['total']:
                 logging.warn('[TCP] server listen port [%s] used traffic is over the setting value' % self._listen_port)
                 self.close()
     if sock == self._server_socket:
         if event & eventloop.POLL_ERR:
             # TODO
             raise Exception('server_socket error')
             common.error_to_file("server_socket error",self._config)
         try:
             logging.debug('accept')
             conn = self._server_socket.accept()
             TCPRelayHandler(self, self._fd_to_handlers,
                             self._eventloop, conn[0], self._config,
                             self._dns_resolver, self._is_local)
         except (OSError, IOError) as e:
             error_no = eventloop.errno_from_exception(e)
             if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                             errno.EWOULDBLOCK):
                 return
             else:
                 shell.print_exception(e)
                 if self._config['verbose']:
                     traceback.print_exc()
     else:
         if sock:
             handler = self._fd_to_handlers.get(fd, None)
             if handler:
                 handler.handle_event(sock, event)
         else:
             logging.warn('poll removed fd')
             common.error_to_file('poll removed fd',self._config)
예제 #17
0
파일: tcprelay.py 프로젝트: able8/ss
 def _sweep_timeout(self):
     logging.debug("Running in the TCPRelay class  [_sweep_timeout]")
     # tornado's timeout memory management is more flexible than we need
     # we just need a sorted last_activity queue and it's faster than heapq
     # in fact we can do O(1) insertion/remove so we invent our own
     if self._timeouts:
         logging.debug("LOGGING sweeping timeouts")
         now = time.time()
         length = len(self._timeouts)
         # print("length of server._timeouts is: %s" % length)
         pos = self._timeout_offset
         while pos < length:
             handler = self._timeouts[pos]
             if handler:
                 if now - handler.last_activity < self._timeout:
                     break
                 else:
                     if handler.remote_address:
                         logging.warn('timed out: %s:%d' %
                                      (handler.remote_address))
                         common.error_to_file('timed out: %s:%d' % (handler.remote_address),self._config)
                     else:
                         logging.warn('timed out some handler')
                         common.error_to_file('timed out some handler',self._config)
                     handler.destroy()
                     self._timeouts[pos] = None  # free memory
                     pos += 1
             else:
                 pos += 1
         if pos > TIMEOUTS_CLEAN_SIZE and pos > length >> 1:
             # clean up the timeout queue when it gets larger than half
             # of the queue
             self._timeouts = self._timeouts[pos:]
             for key in self._handler_to_timeouts:
                 self._handler_to_timeouts[key] -= pos
             pos = 0
         self._timeout_offset = pos
예제 #18
0
파일: tcprelay.py 프로젝트: able8/ss
 def _handle_stage_connecting(self, data):
     logging.debug("Running in the TCPRelayHandler class. [_handle_stage_connecting]")
     if self._is_local:
         data = self._encryptor.encrypt(data)
     self._data_to_write_to_remote.append(data)
     if self._is_local and not self._fastopen_connected and self._config['fast_open']:
         # for sslocal and fastopen, we basically wait for data and use
         # sendto to connect
         try:
             # only connect once
             self._fastopen_connected = True
             remote_sock = self._create_remote_socket(
                 self._chosen_server[0], self._chosen_server[1])
             self._loop.add(remote_sock, eventloop.POLL_ERR, self._server)
             data = b''.join(self._data_to_write_to_remote)
             l = len(data)
             s = remote_sock.sendto(data, MSG_FASTOPEN, self._chosen_server)
             if s < l:
                 data = data[s:]
                 self._data_to_write_to_remote = [data]
             else:
                 self._data_to_write_to_remote = []
             self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
         except (OSError, IOError) as e:
             if eventloop.errno_from_exception(e) == errno.EINPROGRESS:
                 # in this case data is not sent at all
                 self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
             elif eventloop.errno_from_exception(e) == errno.ENOTCONN:
                 logging.error('fast open not supported on this OS')
                 common.error_to_file('fast open not supported on this OS',self._config)
                 self._config['fast_open'] = False
                 self.destroy()
             else:
                 shell.print_exception(e)
                 if self._config['verbose']:
                     traceback.print_exc()
                 self.destroy()
예제 #19
0
    def __init__(self, config):
        self._config = config
        self._relays = {}  # (tcprelay, udprelay)
        self._loop = eventloop.EventLoop()
        self._dns_resolver = asyncdns.DNSResolver()
        self._dns_resolver.add_to_loop(self._loop)

        self._statistics = collections.defaultdict(int)
        self._control_client_addr = None
        try:
            manager_address = config['manager_address']
            if ':' in manager_address:
                addr = manager_address.split(':')
                addr = addr[0], int(addr[1])
                family = socket.AF_INET
            else:
                addr = manager_address
                family = socket.AF_UNIX
            self._control_socket = socket.socket(family, socket.SOCK_DGRAM)
            self._control_socket.bind(addr)
            self._control_socket.setblocking(False)
        except (OSError, IOError) as e:
            logging.error(e)
            logging.error('can not bind to manager address')
            common.error_to_file('can not bind to manager address',
                                 self._config)
            exit(1)
        self._loop.add(self._control_socket, eventloop.POLL_IN, self)
        self._loop.add_periodic(self.handle_periodic)

        port_password = config['port_password']
        del config['port_password']
        for port, password in port_password.items():
            a_config = config.copy()
            a_config['server_port'] = int(port)
            a_config['password'] = password
            self.add_port(a_config)
예제 #20
0
파일: tcprelay.py 프로젝트: able8/ss
 def _log_error(self, e):
     logging.error('%s when handling connection from %s:%d' % (
         common.to_str(e.message), self._client_address[0], self._client_address[1]))
     common.error_to_file('%s when handling connection from %s:%d' % (common.to_str(e.message), self._client_address[0], self._client_address[1]),self._config)
예제 #21
0
파일: tcprelay.py 프로젝트: able8/ss
 def _handle_stage_addr(self, data):
     logging.debug("Running in the TCPRelayHandler class. [_handle_stage_addr]")
     try:
         if self._is_local:
             cmd = common.ord(data[1])
             if cmd == CMD_UDP_ASSOCIATE:
                 logging.debug('UDP associate')
                 if self._local_sock.family == socket.AF_INET6:
                     header = b'\x05\x00\x00\x04'
                 else:
                     header = b'\x05\x00\x00\x01'
                 addr, port = self._local_sock.getsockname()[:2]
                 addr_to_send = socket.inet_pton(
                     self._local_sock.family, addr)
                 port_to_send = struct.pack('>H', port)
                 self._write_to_sock(
                     header + addr_to_send + port_to_send, self._local_sock)
                 self._stage = STAGE_UDP_ASSOC
                 # just wait for the client to disconnect
                 return
             elif cmd == CMD_CONNECT:
                 # just trim VER CMD RSV
                 data = data[3:]
             else:
                 logging.error('unknown command %d' % cmd)
                 common.error_to_file('unknown command %d' % cmd,self._config)
                 self.destroy()
                 return
         header_result = parse_header(data,self._config)
         if header_result is None:
             raise Exception('can not parse header')
         addrtype, remote_addr, remote_port, header_length = header_result
         logging.info('connecting %s:%d from %s:%d' % (common.to_str(
             remote_addr), remote_port, self._client_address[0], self._client_address[1]))
         if self._server._listen_port in self._config['forbid']['port']:
             for i in self._config['forbid']['site']:
                 if str(i) in common.to_str(remote_addr):
                     self.destroy()
         try:
             if common.to_str(self._config['log']['log_enable']) == "True":
                 log_str_one_line = '''[%s]\t%s:%d\t%s:%d [server_port: %s]\n''' % (time.strftime(
                     "%Y-%m-%d %H:%M:%S"), common.to_str(remote_addr), remote_port, self._client_address[0], self._client_address[1],self._server._listen_port)
                 log_str_buf.append(log_str_one_line)
                 if os.path.exists(os.path.split(self._config['log']['log_path'])[0]) is False:
                     os.makedirs(os.path.split(self._config['log']['log_path'])[0])
                 if len(log_str_buf) == 10:
                     f = open("%s" % self._config['log']['log_path'], 'a+')
                     f.write("".join(log_str_buf))
                     f.close()
                     del log_str_buf[:]
         except Exception as e:
             logging.error(
                 "Sorry.Some ERROR happend when I try to log something to file : info: %s" % str(e))
             common.error_to_file("Sorry.Some ERROR happend when I try to log something to file : info: %s" % str(e),self._config)
         self._remote_address = (common.to_str(remote_addr), remote_port)
         # pause reading
         self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
         self._stage = STAGE_DNS
         if self._is_local:
             # forward address to remote
             self._write_to_sock(
                 (b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock)
             data_to_send = self._encryptor.encrypt(data)
             self._data_to_write_to_remote.append(data_to_send)
             # notice here may go into _handle_dns_resolved directly
             self._dns_resolver.resolve(
                 self._chosen_server[0], self._handle_dns_resolved)
         else:
             if len(data) > header_length:
                 self._data_to_write_to_remote.append(data[header_length:])
             # notice here may go into _handle_dns_resolved directly
             self._dns_resolver.resolve(
                 remote_addr, self._handle_dns_resolved)
     except Exception as e:
         self._log_error(e)
         if self._config['verbose']:
             traceback.print_exc()
         # TODO use logging when debug completed
         self.destroy()
예제 #22
0
파일: udprelay.py 프로젝트: able8/ss
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                common.error_to_file('drop a message since frag is not 0',self._config)
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data,self._config)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            server_addr, server_port = self._get_a_server()
        else:
            server_addr, server_port = dest_addr, dest_port

        addrs = self._dns_cache.get(server_addr, None)
        if addrs is None:
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:
                # drop
                return
            else:
                self._dns_cache[server_addr] = addrs

        af, socktype, proto, canonname, sa = addrs[0]
        key = client_key(r_addr, af)

        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return
            client = socket.socket(af, socktype, proto)
            client.setblocking(False)
            self._cache[key] = client
            self._client_fd_to_server_addr[client.fileno()] = r_addr

            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN, self)
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
            if not self._is_local:
                if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
                    port_limits = json.loads(open(self._config['port_limit']).read())
                    if str(self._listen_port) in port_limits:
                        port_limits['%s' % self._listen_port]['used'] = port_limits['%s' % self._listen_port]['used'] + len(data) + BUF_SIZE
                        open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)