コード例 #1
0
    def _handle_server_dns_resolved(self, error, remote_addr, server_addr, params):
        if error:
            return
        data, r_addr, uid, header_length, is_relay = params
        if uid is None:
            is_mu = False
            user_id = self._listen_port
        else:
            is_mu = True
            user_id = uid
        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._disconnect_ipset:
                    if common.to_str(sa[0]) in self._disconnect_ipset:
                        logging.debug('IP %s is in disconnect 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

                if is_mu:
                    if self.multi_user_table[uid]['_forbidden_iplist']:
                        if common.to_str(sa[0]) in self.multi_user_table[uid]['_forbidden_iplist']:
                            logging.debug('IP %s is in forbidden list, drop' % common.to_str(sa[0]))
                            # drop
                            return
                    if self.multi_user_table[uid]['_disconnect_ipset']:
                        if common.to_str(sa[0]) in self.multi_user_table[uid]['_disconnect_ipset']:
                            logging.debug('IP %s is in disconnect list, drop' % common.to_str(sa[0]))
                            # drop
                            return
                    if self.multi_user_table[uid]['_forbidden_portset']:
                        if sa[1] in self.multi_user_table[uid]['_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_relay)
                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 not self.is_pushing_detect_text_list:
                    for id in self.detect_text_list:
                        if common.match_regex(
                                self.detect_text_list[id]['regex'],
                                str(data)):
                            if self._config['is_multi_user'] != 0 and uid != 0:
                                if self.is_cleaning_mu_detect_log_list == False and id not in self.mu_detect_log_list[
                                        uid]:
                                    self.mu_detect_log_list[uid].append(id)
                            else:
                                if self.is_cleaning_detect_log == False and id not in self.detect_log_list:
                                    self.detect_log_list.append(id)
                            raise Exception(
                                'This connection match the regex: id:%d was reject,regex: %s ,connecting %s:%d from %s:%d via port %d' %
                                (self.detect_text_list[id]['id'],
                                 self.detect_text_list[id]['regex'],
                                    common.to_str(server_addr),
                                    server_port,
                                    r_addr[0],
                                    r_addr[1],
                                    self._listen_port))
                if not self.is_pushing_detect_hex_list:
                    for id in self.detect_hex_list:
                        if common.match_regex(
                                self.detect_hex_list[id]['regex'],
                                binascii.hexlify(data)):
                            if self._config['is_multi_user'] != 0 and uid != 0:
                                if self.is_cleaning_mu_detect_log_list == False and id not in self.mu_detect_log_list[
                                        uid]:
                                    self.mu_detect_log_list[uid].append(id)
                            else:
                                if self.is_cleaning_detect_log == False and id not in self.detect_log_list:
                                    self.detect_log_list.append(id)
                            raise Exception(
                                'This connection match the regex: id:%d was reject,regex: %s ,connecting %s:%d from %s:%d via port %d' %
                                (self.detect_hex_list[id]['id'],
                                 self.detect_hex_list[id]['regex'],
                                    common.to_str(server_addr),
                                    server_port,
                                    r_addr[0],
                                    r_addr[1],
                                    self._listen_port))
                if not self._connect_hex_data:
                    common.connect_log('UDP data to %s:%d from %s:%d via port %d' %
                                       (common.to_str(server_addr), server_port,
                                        r_addr[0], r_addr[1], self._listen_port))
                else:
                    common.connect_log(
                        'UDP data to %s:%d from %s:%d via port %d,hex data : %s' %
                        (common.to_str(server_addr),
                         server_port,
                         r_addr[0],
                            r_addr[1],
                            self._listen_port,
                            binascii.hexlify(data)))
                if self._config['is_multi_user'] != 2:
                    if common.to_str(r_addr[0]) in self.wrong_iplist and r_addr[
                            0] != 0 and self.is_cleaning_wrong_iplist == False:
                        del self.wrong_iplist[common.to_str(r_addr[0])]
                    if common.getRealIp(r_addr[0]) not in self.connected_iplist and r_addr[
                            0] != 0 and self.is_cleaning_connected_iplist == False:
                        self.connected_iplist.append(common.getRealIp(r_addr[0]))
            else:
                client, client_uid = client_pair
            self._cache.clear(self._udp_cache_size)
            self._cache_dns_client.clear(16)

            if self._is_local:
                try:
                    key, ref_iv, m = encrypt.gen_key_iv(self._password, 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_m(key, ref_iv, m, self._method, data)
                except Exception:
                    logging.debug("UDP handle_server: encrypt data failed")
                    return
                if not data:
                    return
            else:
                data = data[header_length:]
            if not data:
                return
        except Exception as e:
            shell.print_exception(e)
            if self._config['verbose']:
                traceback.print_exc()
            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)
コード例 #2
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:
            try:
                data, key, ref_iv = encrypt.decrypt_all(self._password,
                                                    self._method,
                                                    data)
            except Exception:
                logging.debug('UDP handle_server: decrypt data failed')
                return

            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
            ref_iv = [0]
            self._protocol.obfs.server_info.recv_iv = ref_iv[0]
            data, uid = self._protocol.server_udp_post_decrypt(data)

            if self._config['is_multi_user'] != 0 and data:
                if uid:
                    if uid not in self.mu_server_transfer_ul:
                        self.mu_server_transfer_ul[uid] = 0
                    if uid not in self.mu_server_transfer_dl:
                        self.mu_server_transfer_dl[uid] = 0
                    if uid not in self.mu_connected_iplist:
                        self.mu_connected_iplist[uid] = []
                    if uid not in self.mu_detect_log_list:
                        self.mu_detect_log_list[uid] = []

                    if common.getRealIp(r_addr[0]) not in self.mu_connected_iplist[uid]:
                        self.mu_connected_iplist[uid].append(common.getRealIp(r_addr[0]))

                else:
                    raise Exception(
                        'This port is multi user in single port only,so The connection has been rejected, when connect from %s:%d via port %d' %
                        (r_addr[0], r_addr[1], self._listen_port))

        is_relay = False

        #logging.info("UDP data %s" % (binascii.hexlify(data),))
        if not self._is_local:

            if not self._is_relay(r_addr, ogn_data, uid):
                data = pre_parse_header(data)

                data = self._pre_parse_udp_header(data)
                if data is None:
                    return

                if isinstance(data, tuple):
                    return
                    # return self._handle_tcp_over_udp(data, r_addr)
            else:
                if self._config["is_multi_user"] == 0:
                    data, is_relay = self._handel_normal_relay(r_addr, ogn_data)
                else:
                    data, is_relay = self._handel_mu_relay(r_addr, ogn_data, uid)

        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, is_relay))
                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, is_relay))
        else:
            self._handle_server_dns_resolved("", (server_addr, server_port), server_addr, (data, r_addr, uid, header_length, is_relay))