Exemplo n.º 1
0
 def _close_tcp_client(self, client):
     if client.remote_address:
         logging.debug('timed out: %s:%d' % client.remote_address)
     else:
         logging.debug('timed out')
     client.destroy()
     client.destroy_local()
Exemplo n.º 2
0
    def run(self):
        events = []
        while not self._stopping:
            asap = False
            try:
                events = self.poll(TIMEOUT_PRECISION)
            except (OSError, IOError) as e:
                if errno_from_exception(e) in (errno.EPIPE, errno.EINTR):
                    # EPIPE: Happens when the client closes the connection
                    # EINTR: Happens when received a signal
                    # handles them as soon as possible
                    asap = True
                    logging.debug('poll:%s', e)
                else:
                    logging.error('poll:%s', e)
                    import traceback
                    traceback.print_exc()
                    continue

            handle = False
            for sock, fd, event in events:
                handler = self._fdmap.get(fd, None)
                if handler is not None:
                    handler = handler[1]
                    try:
                        handle = handler.handle_event(sock, fd, event) or handle
                    except (OSError, IOError) as e:
                        shell.print_exception(e)
            now = time.time()
            if asap or now - self._last_time >= TIMEOUT_PRECISION:
                for callback in self._periodic_callbacks:
                    callback()
                self._last_time = now
            if events and not handle:
                time.sleep(0.001)
Exemplo n.º 3
0
 def _get_a_server(self):
     server = self._config['server']
     server_port = self._config['server_port']
     if type(server_port) == list:
         server_port = random.choice(server_port)
     if type(server) == list:
         server = random.choice(server)
     logging.debug('chosen server: %s:%d', server, server_port)
     return server, server_port
Exemplo n.º 4
0
 def close(self, next_tick=False):
     logging.debug('UDP close')
     self._closed = True
     if not next_tick:
         if self._eventloop:
             self._eventloop.remove_periodic(self.handle_periodic)
             self._eventloop.remove(self._server_socket)
         self._server_socket.close()
         self._cache.clear(0)
         self._cache_dns_client.clear(0)
Exemplo n.º 5
0
 def auth_data(self):
     utc_time = int(time.time()) & 0xFFFFFFFF
     if self.server_info.data.connection_id > 0xFF000000:
         self.server_info.data.local_client_id = b''
     if not self.server_info.data.local_client_id:
         self.server_info.data.local_client_id = rand_bytes(4)
         logging.debug("local_client_id %s" % (binascii.hexlify(self.server_info.data.local_client_id),))
         self.server_info.data.connection_id = struct.unpack('<I', rand_bytes(4))[0] & 0xFFFFFF
     self.server_info.data.connection_id += 1
     return b''.join([struct.pack('<I', utc_time),
                      self.server_info.data.local_client_id,
                      struct.pack('<I', self.server_info.data.connection_id)])
Exemplo n.º 6
0
 def _close_client(self, client):
     if hasattr(client, 'close'):
         if not self._is_local:
             if client.fileno() in self._client_fd_to_server_addr:
                 logging.debug(
                     'close_client: %s' %
                     (self._client_fd_to_server_addr[client.fileno()], ))
             else:
                 client.info('close_client')
         self._sockets.remove(client.fileno())
         self._eventloop.remove(client)
         del self._client_fd_to_server_addr[client.fileno()]
         client.close()
     else:
         # just an address
         client.info('close_client pass %s' % client)
         pass
Exemplo n.º 7
0
 def __init__(self):
     if hasattr(select, 'epoll'):
         self._impl = select.epoll()
         model = 'epoll'
     elif hasattr(select, 'kqueue'):
         self._impl = KqueueLoop()
         model = 'kqueue'
     elif hasattr(select, 'select'):
         self._impl = SelectLoop()
         model = 'select'
     else:
         raise Exception('can not find any available functions in select '
                         'package')
     self._fdmap = {}  # (f, handler)
     self._last_time = time.time()
     self._periodic_callbacks = []
     self._stopping = False
     logging.debug('using event model: %s', model)
Exemplo n.º 8
0
 def handle_periodic(self):
     if self._closed:
         self._cache.clear(0)
         self._cache_dns_client.clear(0)
         if self._eventloop:
             self._eventloop.remove_periodic(self.handle_periodic)
             self._eventloop.remove(self._server_socket)
         if self._server_socket:
             self._server_socket.close()
             self._server_socket = None
             logging.info('closed UDP port %d', self._listen_port)
     else:
         before_sweep_size = len(self._sockets)
         self._cache.sweep()
         self._cache_dns_client.sweep()
         if before_sweep_size != len(self._sockets):
             logging.debug('UDP port %5d sockets %d' %
                           (self._listen_port, len(self._sockets)))
         self._sweep_timeout()
Exemplo n.º 9
0
    def _socket_bind_addr(self, sock, af):
        bind_addr = ''
        if self._bind and af == socket.AF_INET:
            bind_addr = self._bind
        elif self._bindv6 and af == socket.AF_INET6:
            bind_addr = self._bindv6

        bind_addr = bind_addr.replace("::ffff:", "")
        if bind_addr in self._ignore_bind_list:
            bind_addr = None
        if bind_addr:
            local_addrs = socket.getaddrinfo(bind_addr, 0, 0,
                                             socket.SOCK_DGRAM, socket.SOL_UDP)
            if local_addrs[0][0] == af:
                logging.debug("bind %s" % (bind_addr, ))
                try:
                    sock.bind((bind_addr, 0))
                except Exception as e:
                    logging.warn("bind %s fail" % (bind_addr, ))
Exemplo n.º 10
0
    def server_decode(self, buf):
        if self.has_recv_header:
            return (buf, True, False)

        self.recv_buffer += buf
        buf = self.recv_buffer
        if len(buf) > 10:
            if match_begin(buf, b'GET ') or match_begin(buf, b'POST '):
                if len(buf) > 65536:
                    self.recv_buffer = None
                    logging.warn('http_simple: over size')
                    return self.not_match_return(buf)
            else:  #not http header, run on original protocol
                self.recv_buffer = None
                logging.debug('http_simple: not match begin')
                return self.not_match_return(buf)
        else:
            return (b'', True, False)

        if b'\r\n\r\n' in buf:
            datas = buf.split(b'\r\n\r\n', 1)
            ret_buf = self.get_data_from_http_header(buf)
            host = self.get_host_from_http_header(buf)
            if host and self.server_info.obfs_param:
                pos = host.find(":")
                if pos >= 0:
                    host = host[:pos]
                hosts = self.server_info.obfs_param.split(',')
                if host not in hosts:
                    return self.not_match_return(buf)
            if len(ret_buf) < 4:
                return self.error_return(buf)
            if len(datas) > 1:
                ret_buf += datas[1]
            if len(ret_buf) >= 13:
                self.has_recv_header = True
                return (ret_buf, True, False)
            return self.not_match_return(buf)
        else:
            return (b'', True, False)
Exemplo n.º 11
0
def get_config(is_local):
    global verbose
    config = {}
    config_path = None
    logging.basicConfig(level=logging.INFO,
                        format='%(levelname)-s: %(message)s')
    if is_local:
        shortopts = 'hd:s:b:p:k:l:m:O:o:G:g:c:t:vq'
        longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'user='******'version']
    else:
        shortopts = 'hd:s:p:k:m:O:o:G:g:c:t:vq'
        longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'workers=',
                    'forbidden-ip=', 'user='******'manager-address=', 'version']
    try:
        optlist, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
        for key, value in optlist:
            if key == '-c':
                config_path = value
            elif key in ('-h', '--help'):
                print_help(is_local)
                sys.exit(0)
            elif key == '--version':
                print_shadowsocks()
                sys.exit(0)
            else:
                continue

        if config_path is None:
            config_path = find_config()

        if config_path:
            logging.debug('loading config from %s' % config_path)
            with open(config_path, 'rb') as f:
                try:
                    config = parse_json_in_str(remove_comment(f.read().decode('utf8')))
                except ValueError as e:
                    logging.error('found an error in config.json: %s', str(e))
                    sys.exit(1)

        v_count = 0
        for key, value in optlist:
            if key == '-p':
                config['server_port'] = int(value)
            elif key == '-k':
                config['password'] = to_bytes(value)
            elif key == '-l':
                config['local_port'] = int(value)
            elif key == '-s':
                config['server'] = to_str(value)
            elif key == '-m':
                config['method'] = to_str(value)
            elif key == '-O':
                config['protocol'] = to_str(value)
            elif key == '-o':
                config['obfs'] = to_str(value)
            elif key == '-G':
                config['protocol_param'] = to_str(value)
            elif key == '-g':
                config['obfs_param'] = to_str(value)
            elif key == '-b':
                config['local_address'] = to_str(value)
            elif key == '-v':
                v_count += 1
                # '-vv' turns on more verbose mode
                config['verbose'] = v_count
            elif key == '-t':
                config['timeout'] = int(value)
            elif key == '--fast-open':
                config['fast_open'] = True
            elif key == '--workers':
                config['workers'] = int(value)
            elif key == '--manager-address':
                config['manager_address'] = value
            elif key == '--user':
                config['user'] = to_str(value)
            elif key == '--forbidden-ip':
                config['forbidden_ip'] = to_str(value)

            elif key == '-d':
                config['daemon'] = to_str(value)
            elif key == '--pid-file':
                config['pid-file'] = to_str(value)
            elif key == '--log-file':
                config['log-file'] = to_str(value)
            elif key == '-q':
                v_count -= 1
                config['verbose'] = v_count
            else:
                continue
    except getopt.GetoptError as e:
        print(e, file=sys.stderr)
        print_help(is_local)
        sys.exit(2)

    if not config:
        logging.error('config not specified')
        print_help(is_local)
        sys.exit(2)

    config['password'] = to_bytes(config.get('password', b''))
    config['method'] = to_str(config.get('method', 'aes-256-cfb'))
    config['protocol'] = to_str(config.get('protocol', 'origin'))
    config['protocol_param'] = to_str(config.get('protocol_param', ''))
    config['obfs'] = to_str(config.get('obfs', 'plain'))
    config['obfs_param'] = to_str(config.get('obfs_param', ''))
    config['port_password'] = config.get('port_password', None)
    config['additional_ports'] = config.get('additional_ports', {})
    config['additional_ports_only'] = config.get('additional_ports_only', False)
    config['timeout'] = int(config.get('timeout', 300))
    config['udp_timeout'] = int(config.get('udp_timeout', 120))
    config['udp_cache'] = int(config.get('udp_cache', 64))
    config['fast_open'] = config.get('fast_open', False)
    config['workers'] = config.get('workers', 1)
    config['pid-file'] = config.get('pid-file', '/var/run/shadowsocksr.pid')
    config['log-file'] = config.get('log-file', '/var/log/shadowsocksr.log')
    config['verbose'] = config.get('verbose', False)
    config['connect_verbose_info'] = config.get('connect_verbose_info', 0)
    config['local_address'] = to_str(config.get('local_address', '127.0.0.1'))
    config['local_port'] = config.get('local_port', 1080)
    if is_local:
        if config.get('server', None) is None:
            logging.error('server addr not specified')
            print_local_help()
            sys.exit(2)
        else:
            config['server'] = to_str(config['server'])
    else:
        config['server'] = to_str(config.get('server', '0.0.0.0'))
        config['black_hostname_list'] = to_str(config.get('black_hostname_list', '')).split(',')
        if len(config['black_hostname_list']) == 1 and config['black_hostname_list'][0] == '':
            config['black_hostname_list'] = []
        try:
            config['forbidden_ip'] = \
                IPNetwork(config.get('forbidden_ip', '127.0.0.0/8,::1/128'))
        except Exception as e:
            logging.error(e)
            sys.exit(2)
        try:
            config['forbidden_port'] = PortRange(config.get('forbidden_port', ''))
        except Exception as e:
            logging.error(e)
            sys.exit(2)
        try:
            config['ignore_bind'] = \
                IPNetwork(config.get('ignore_bind', '127.0.0.0/8,::1/128,10.0.0.0/8,192.168.0.0/16'))
        except Exception as e:
            logging.error(e)
            sys.exit(2)
    config['server_port'] = config.get('server_port', 8388)

    logging.getLogger('').handlers = []
    logging.addLevelName(VERBOSE_LEVEL, 'VERBOSE')
    if config['verbose'] >= 2:
        level = VERBOSE_LEVEL
    elif config['verbose'] == 1:
        level = logging.DEBUG
    elif config['verbose'] == -1:
        level = logging.WARN
    elif config['verbose'] <= -2:
        level = logging.ERROR
    else:
        level = logging.INFO
    verbose = config['verbose']
    logging.basicConfig(level=level,
                        format='%(asctime)s %(levelname)-8s %(filename)s:%(lineno)s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')

    check_config(config, is_local)

    return config
Exemplo n.º 12
0
    def _handle_client(self, sock):
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))

        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        client_uid = None
        if client_addr:
            key = client_key(client_addr[0], client_addr[1])
            client_pair = self._cache.get(key, None)
            client_dns_pair = self._cache_dns_client.get(key, None)
            if client_pair:
                client, client_uid = client_pair
            elif client_dns_pair:
                client, client_uid = client_dns_pair

        if not self._is_local:
            addrlen = len(r_addr[0])
            if addrlen > 255:
                # drop
                return
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            ref_iv = [encrypt.encrypt_new_iv(self._method)]
            self._protocol.obfs.server_info.iv = ref_iv[0]
            data = self._protocol.server_udp_pre_encrypt(data, client_uid)
            response = encrypt.encrypt_all_iv(
                self._protocol.obfs.server_info.key, self._method, 1, data,
                ref_iv)
            if not response:
                return
        else:
            ref_iv = [0]
            data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key,
                                          self._method, 0, data, ref_iv)
            if not data:
                return
            self._protocol.obfs.server_info.recv_iv = ref_iv[0]
            data = self._protocol.client_udp_post_decrypt(data)
            header_result = parse_header(data)
            if header_result is None:
                return
            #connecttype, dest_addr, dest_port, header_length = header_result
            #logging.debug('UDP handle_client %s:%d to %s:%d' % (common.to_str(r_addr[0]), r_addr[1], dest_addr, dest_port))

            response = b'\x00\x00\x00' + data

        if client_addr:
            if client_uid:
                self.add_transfer_d(client_uid, len(response))
            else:
                self.server_transfer_dl += len(response)
            self.write_to_server_socket(response, client_addr[0])
            if client_dns_pair:
                logging.debug("remove dns client %s:%d" %
                              (client_addr[0][0], client_addr[0][1]))
                del self._cache_dns_client[key]
                self._close_client(client_dns_pair[0])
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
Exemplo n.º 13
0
    def _handle_server_dns_resolved(self, error, remote_addr, server_addr,
                                    params):
        if error:
            return
        data, r_addr, uid, header_length = params
        user_id = self._listen_port
        try:
            server_port = remote_addr[1]
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:  # drop
                return
            af, socktype, proto, canonname, sa = addrs[0]
            server_addr = sa[0]
            key = client_key(r_addr, af)
            client_pair = self._cache.get(key, None)
            if client_pair is None:
                client_pair = self._cache_dns_client.get(key, None)
            if client_pair is None:
                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
                if self._forbidden_portset:
                    if sa[1] in self._forbidden_portset:
                        logging.debug('Port %d is in forbidden list, reject' %
                                      sa[1])
                        # drop
                        return
                client = socket.socket(af, socktype, proto)
                client_uid = uid
                client.setblocking(False)
                self._socket_bind_addr(client, af)
                is_dns = False
                if len(data) > header_length + 13 and data[
                        header_length + 4:header_length +
                        12] == b"\x00\x01\x00\x00\x00\x00\x00\x00":
                    is_dns = True
                else:
                    pass
                if sa[1] == 53 and is_dns:  #DNS
                    logging.debug("DNS query %s from %s:%d" %
                                  (common.to_str(sa[0]), r_addr[0], r_addr[1]))
                    self._cache_dns_client[key] = (client, uid)
                else:
                    self._cache[key] = (client, uid)
                self._client_fd_to_server_addr[client.fileno()] = (r_addr, af)

                self._sockets.add(client.fileno())
                self._eventloop.add(client, eventloop.POLL_IN, self)

                logging.debug('UDP port %5d sockets %d' %
                              (self._listen_port, len(self._sockets)))

                if uid is not None:
                    user_id = struct.unpack('<I', client_uid)[0]
            else:
                client, client_uid = client_pair
            self._cache.clear(self._udp_cache_size)
            self._cache_dns_client.clear(16)

            if self._is_local:
                ref_iv = [encrypt.encrypt_new_iv(self._method)]
                self._protocol.obfs.server_info.iv = ref_iv[0]
                data = self._protocol.client_udp_pre_encrypt(data)
                #logging.debug("%s" % (binascii.hexlify(data),))
                data = encrypt.encrypt_all_iv(
                    self._protocol.obfs.server_info.key, self._method, 1, data,
                    ref_iv)
                if not data:
                    return
            else:
                data = data[header_length:]
            if not data:
                return
        except Exception as e:
            shell.print_exception(e)
            logging.error("exception from user %d" % (user_id, ))

        try:
            client.sendto(data, (server_addr, server_port))
            self.add_transfer_u(client_uid, len(data))
            if client_pair is None:  # new request
                addr, port = client.getsockname()[:2]
                common.connect_log(
                    'UDP data to %s(%s):%d from %s:%d by user %d' %
                    (common.to_str(remote_addr[0]), common.to_str(server_addr),
                     server_port, addr, port, user_id))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            logging.warning('IOError sendto %s:%d by user %d' %
                            (server_addr, server_port, user_id))
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Exemplo n.º 14
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        ogn_data = data
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        uid = None
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            ref_iv = [0]
            data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key,
                                          self._method, 0, data, ref_iv)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
            self._protocol.obfs.server_info.recv_iv = ref_iv[0]
            data, uid = self._protocol.server_udp_post_decrypt(data)

        #logging.info("UDP data %s" % (binascii.hexlify(data),))
        if not self._is_local:
            data = pre_parse_header(data)
            if data is None:
                return

        try:
            header_result = parse_header(data)
        except:
            self._handel_protocol_error(r_addr, ogn_data)
            return

        if header_result is None:
            self._handel_protocol_error(r_addr, ogn_data)
            return
        connecttype, addrtype, dest_addr, dest_port, header_length = header_result

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

        if (addrtype & 7) == 3:
            af = common.is_ip(server_addr)
            if af == False:
                handler = common.UDPAsyncDNSHandler(
                    (data, r_addr, uid, header_length))
                handler.resolve(self._dns_resolver, (server_addr, server_port),
                                self._handle_server_dns_resolved)
            else:
                self._handle_server_dns_resolved(
                    "", (server_addr, server_port), server_addr,
                    (data, r_addr, uid, header_length))
        else:
            self._handle_server_dns_resolved(
                "", (server_addr, server_port), server_addr,
                (data, r_addr, uid, header_length))