예제 #1
0
    def send_alive_pkg1(self):
        """
        发送类型一的心跳包
        :return:
        """
        pkg = b'\xff'
        pkg += md5(b'\x03\x01' + self.salt + self.pwd.encode('ascii'))  # MD5_A
        pkg += b'\x00' * 3
        pkg += self.auth_info
        pkg += struct.pack('!H', int(time.time()) % 0xFFFF)
        pkg += b'\x00' * 3

        data, address = self._send_package(pkg, (self.server_ip, 61440))

        if data[0] == 0x07:
            Log(
                logging.DEBUG, 0,
                "[DrCOM.send_alive_pkg1]:Successful sending heartbeat package type 1..."
            )
        else:
            # 当收到的数据包没法识别的时候,标记当前状态已经为掉线状态
            Log(
                logging.ERROR, 40,
                "[DrCOM.send_alive_pkg1]:Receive unknown packages content: {}".
                format(data))
            self.alive_flag = False
예제 #2
0
    def send_alive_pkg2(self, num, key, cls):
        """
        发送类型二的心跳包
        :return:
        """
        response = 0
        pkg = self._make_alive_package(num=num, key=key, cls=cls)

        data, address = self._send_package(pkg, (self.server_ip, 61440))

        if data[0] == 0x07:
            Log(
                logging.DEBUG, 0,
                "[DrCOM.send_alive_pkg2]:Successful sending heartbeat package 2[{}]..."
                .format(cls))
            response = data[16:20]
        else:
            # 当收到的数据包没法识别的时候,标记当前状态已经为掉线状态
            Log(
                logging.ERROR, 50,
                "[DrCOM.send_alive_pkg2]:Receive unknown packages content: {}".
                format(data))
            self.alive_flag = False

        return response
예제 #3
0
    def __initialise__(self):
        """
        尝试获取当前主机的主机名称、MAC地址、联网IP地址
        :return:
        """
        self.host_name = hostname()

        if LOCAL_MAC:  # 如果没有指定本机MAC,尝试自动获取
            self.mac = bytes().fromhex(LOCAL_MAC)
        else:
            self.mac = bytes().fromhex(mac())

        if LOCAL_IP:  # 如果没有指定本机IP,尝试自动获取
            self.ip = LOCAL_IP
        else:
            self.ip = ipaddress()

        if not self.host_name or not self.mac or not self.ip:
            Log(logging.ERROR, 10,
                "[DrCOM.__init__]:无法获取本机的NIC信息,请直接提交到该项目issues")
            raise DrCOMException("无法获取本机的NIC信息")

        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
                                    socket.IPPROTO_UDP)
        self.socket.settimeout(3)
        try:
            self.socket.bind(("", 61440))
        except socket.error:
            Log(logging.ERROR, 10,
                "[DrCOM.__init__]:无法绑定61440端口,请检查是否有其他进程占据了该端口")
            raise DrCOMException("无法绑定本机61440端口")
예제 #4
0
 def logout(self):
     Log(logging.INFO, 0,
         "[MagicDrCOM.logout]:Sending logout request to DrCOM Server")
     try:
         self._client.logout()
         self._client.interrupt = True
         Log(logging.INFO, 0,
             "[MagicDrCOM.logout]:Successful logout to DrCOM Server")
     except (DrCOMException, TimeoutException) as exc:
         raise MagicDrCOMException("Failure on logout: " + exc.info)
예제 #5
0
    def _send_package(self, pkg, server):
        """
        发送数据包, 每次发送都尝试三次,如果发送三次都失败,触发超时异常
        :param pkg:
        :return:
        """
        last_times = ReTryTimes
        while last_times > 0 and not self.interrupt:
            last_times = last_times - 1
            clean_socket_buffer(self.socket)
            self.socket.sendto(pkg, server)
            try:
                data, address = self.socket.recvfrom(1024)
            except socket.timeout:
                Log(
                    logging.WARNING, 0,
                    "[DrCOM._send_package]:Continue to retry times [{}]...".
                    format(last_times))
                continue

            if data and address:
                return data, address

        if self.interrupt:
            exception = TimeoutException(
                "[DrCOM._send_package]:Failure on sending package...")
            exception.last_pkg = pkg
            raise exception
예제 #6
0
    def send_alive_pkg1(self):
        """
        发送类型一的心跳包
        :return:
        """
        pkg = b'\xff'
        pkg += md5(b'\x03\x01' + self.salt + self.pwd.encode('ascii'))  # MD5_A
        pkg += b'\x00' * 3
        pkg += self.auth_info
        pkg += struct.pack('!H', int(time.time()) % 0xFFFF)
        pkg += b'\x00' * 3

        data, address = self._send_package(pkg, (self.server_ip, 61440))

        if data[0] == 0x07:
            Log(
                logging.DEBUG, 0,
                "[DrCOM.send_alive_pkg1]:Successful sending heartbeat package type 1..."
            )
        else:
            # 当收到的数据包没法识别的时候
            exception = DrCOMException(
                "[DrCOM.send_alive_pkg1]:Receive unknown packages content...")
            exception.last_pkg = data
            raise exception
예제 #7
0
    def _login(self):
        if self._client.usr == "" or self._client.pwd == "":
            raise MagicDrCOMException(
                "Please enter your username and password...")

        Log(logging.INFO, 0, "[MagicDrCOM.login]:Starting login...")
        try:
            self._client.prepare()
            self._client.login()
            keep_alive_thread = threading.Thread(
                target=self._client.keep_alive, args=())
            keep_alive_thread.start()
            Log(logging.INFO, 0,
                "[MagicDrCOM.login]:Successfully login to server...")
        except (DrCOMException, TimeoutException) as exc:
            raise MagicDrCOMException("Failure on login: " + exc.info)
예제 #8
0
    def logout(self):
        """
        登出,仅测试了BISTU版本
        登出过程一共会有6个包,分3组,每组2个
        第一组同alive_pkg1的发送与确认
        第二组似乎是用于告知网关准备登出
        第三组会发送登出的详细信息包括用户名等
        """
        # 第一组 初步判断是为了判断当前网络是否联通
        # 发送的数据包的最后两个字节可能有验证功能
        self.send_alive_pkg1()

        # 第二组 登出准备
        # 与alive_pkg1的最后两个字节相同
        pkg = b'\x01\x03'
        pkg += b'\x00\x00'
        pkg += b'\x0a'
        pkg += b'\x00' * 15

        data, address = self._send_package(pkg, (self.server_ip, 61440))

        if data[0:2] != b'\x02\x03':
            Log(
                logging.ERROR, 70,
                "[DrCOM.login]:Receive unknown packages content: {}".format(
                    data))

        # 第三组
        pkg = self._make_logout_package()

        data, address = self._send_package(pkg, (self.server_ip, 61440))

        if data[0] == 0x04:
            self.login_flag = False
        else:
            Log(
                logging.ERROR, 71,
                "[DrCOM.logout]:Receive unknown packages content: {}".format(
                    data))

        if self.login_flag:
            exception = DrCOMException("Failure on logout to DrCOM...")
            exception.last_pkg = pkg
            raise exception
예제 #9
0
 def login(self):
     """
     登录方法
     :return:
     """
     self._login()
     if self.relogin_flag:
         self._set_interval(self.relogin_check, self._daemon)
         Log(logging.INFO, 0,
             "[MagicDrCOM.login]:Starting network check daemon thread...")
예제 #10
0
    def login(self):
        """
        登录到目标服务器方法
        :return:
        """
        pkg = self._make_login_package()

        data, address = self._send_package(pkg, (self.server_ip, 61440))

        Log(logging.DEBUG, 0,
            "[DrCOM.login]:Receive PKG content: {}".format(data))
        if data[0] == 0x04:
            self.auth_info = data[23:39]
            # 在这里设置当前为登录状态并且也处于在线状态
            self.login_flag = True
            self.alive_flag = True
            Log(logging.INFO, 0,
                "[DrCOM.login]:Successfully login to DrCOM Server...")
        elif data[0] == 0x05:
            if len(data) > 32:
                if data[32] == 0x31:
                    Log(
                        logging.ERROR, 31,
                        "[DrCOM.login]:Failure on login because the wrong username..."
                    )
                if data[32] == 0x33:
                    Log(
                        logging.ERROR, 32,
                        "[DrCOM.login]:Failure on login because the wrong password..."
                    )
        else:
            Log(
                logging.ERROR, 30,
                "[DrCOM.login]:Receive unknown packages content: {}".format(
                    data))

        if not self.login_flag:
            exception = DrCOMException("Failure on login to DrCOM...")
            exception.last_pkg = pkg
            raise exception
예제 #11
0
 def relogin(self):
     self.relogin_times -= 1
     if self.relogin_times >= 0:
         Log(
             logging.WARNING, 0,
             "[MagicDrCOM._auto_relogin]:Starting relogin last %d times..."
             % self.relogin_times)
         self._client.logout()
         time.sleep(5)
         self._client.prepare()
         self._client.login()
     else:
         raise MagicDrCOMException("Maximum time reties...")
예제 #12
0
 def _interval_loop(self, period, callback, args):
     """
     模拟事件循环,用来循环调用请求网站方法
     :param period: 间隔时间
     :param callback: 回调方法
     :param args: 参数
     :return:
     """
     try:
         while self._client.login_flag:
             time.sleep(period)
             callback(*args)
     except MagicDrCOMException:
         Log(logging.ERROR, 120, "[MagicDrCOM._auto_relogin]:超出最大重试次数!")
예제 #13
0
 def keep_alive(self):
     num = 0
     key = b'\x00' * 4
     while self.alive_flag:
         try:
             self.send_alive_pkg1()
             key = self.send_alive_pkg2(num, key, cls=1)
             key = self.send_alive_pkg2(num, key, cls=3)
         except TimeoutException as exc:
             Log(logging.ERROR, 60, "[DrCOM.keep_alive]:" + exc.info)
             self.alive_flag = False
             break
         num = num + 2
         time.sleep(10)
예제 #14
0
    def prepare(self):
        """
        获取服务器IP和Salt
        :return:
        """
        random_value = struct.pack(
            "<H",
            int(time.time() + random.randint(0xF, 0xFF)) % 0xFFFF)
        pkg = b'\x01\x02' + random_value + b'\x0a' + b'\x00' * 15

        # 尝试目前已知的学校认证服务器地址
        for _ in [(SERVER_IP, 61440), ("1.1.1.1", 61440),
                  ("202.1.1.1", 61440)]:
            data, address = self._send_package(pkg, _)

            # 未获取合理IP地址则进行下一个服务器地址尝试
            Log(logging.DEBUG, 0,
                "[DrCOM.prepare]:Receive PKG content: {}".format(data))
            if data[0:4] == b'\x02\x02' + random_value:
                self.server_ip = address[0]
                self.salt = data[4:8]
                Log(
                    logging.DEBUG, 0,
                    "[DrCOM.prepare]:Server IP: {}, Salt: {}".format(
                        self.server_ip, self.salt))
                return
            else:
                Log(
                    logging.WARNING, 20,
                    "[DrCOM.prepare]:Receive unknown packages content: {}".
                    format(data))

        if not self.server_ip or not self.salt:
            exception = DrCOMException(
                "[DrCOM.prepare]:Cannot find any available server...")
            exception.last_pkg = pkg
            raise exception
예제 #15
0
 def _daemon(self):
     """
     判断网络连通性的方法
     Host: 114.114.114.114
     OpenPort: 53/tcp
     Service: domain (DNS/TCP)
     """
     try:
         socket.setdefaulttimeout(1)
         socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect(
             ("114.114.114.114", 53))
         Log(logging.INFO, 0,
             "[MagicDrCOM.check]:Successful connect to network...")
         return True
     except socket.error:
         if self.status == DIEOUT:
             self.relogin()
예제 #16
0
    def __init__(self):
        print("欢迎使用BISTU专版的第三方Dr.COM客户端")
        print("本项目目前由@Ryuchen进行开发和维护")
        print("如有任何问题欢迎在本项目的github页面提交issue")
        print("[https://github.com/Ryuchen/MagicDrCOM/issues]")

        self._usr = ""
        self._pwd = ""
        # self._login_flag = False
        self._alive_check = False
        self._relogin_flag = ReLoginFlag
        self._relogin_times = ReLoginTimes
        self._relogin_check = ReLoginCheck

        try:
            self._client = DrCOMClient(self._usr, self._pwd)
        except DrCOMException as exc:
            Log(logging.ERROR, 10,
                "[MagicDrCOMClient.__init__]:无法进行初始化:" + exc.info)
            raise MagicDrCOMException("请检查本机设置之后重试~")
예제 #17
0
    def send_alive_pkg2(self, num, key, cls):
        """
        发送类型二的心跳包
        :return:
        """
        pkg = self._make_alive_package(num=num, key=key, cls=cls)

        data, address = self._send_package(pkg, (self.server_ip, 61440))

        if data[0] == 0x07:
            Log(
                logging.DEBUG, 0,
                "[DrCOM.send_alive_pkg2]:Successful sending heartbeat package 2[{}]..."
                .format(cls))
            response = data[16:20]
            return response
        else:
            # 当收到的数据包没法识别的时候
            exception = DrCOMException(
                "[DrCOM.send_alive_pkg2]:Receive unknown packages content...")
            exception.last_pkg = data
            raise exception