drcoms / drcom-generic

Dr.COM/DrCOM 现已覆盖 d p x三版。
GNU Affero General Public License v3.0
1.15k stars 268 forks source link

广东工业大学(5.2.1p)心跳包错误(heartbeat response failed, retry) #148

Closed Zhicwan closed 8 years ago

Zhicwan commented 8 years ago

今天广东工业大学drcom的心跳包加密进行了更新。 之前一直是使用issue #82 的latest-pppoe.py的版本。 今天心跳包更新后,配置没有改变,但是心跳包更改了。 数据包和客户端文件:http://pan.baidu.com/s/1bpEC3Jx 文件清单: orginal.pcapng 使用官方drcom所抓到的包 Dr.Com.zip 官方drcom客户端 latest-pppoe.py #82 的latest-pppoe.py文件 latest-pppoe_log.pcapng 使用 #82 时所抓到的包 latest-pppoe_log.txt latest-pppoe.py 输出的log

larry0442 commented 8 years ago

难怪我今天一直掉线,以为是校园网大姨妈

lyhyl commented 8 years ago

同样问题,检查过drcom,好像没有更新过,但是目录下有两个每次登陆都会修改的文件[config(没有后缀名),DrLinkConfigure],不知道是不是某种加密方式?

mchome commented 8 years ago

你有试过 https://github.com/drcoms/drcom-generic/blob/master/latest-pppoe.py

Zhicwan commented 8 years ago

试过了。同样的情况。 @mchome

larry0442 commented 8 years ago

@w282200695 OK,已delete

Zhicwan commented 8 years ago

@larry0442 你测试一下贴吧上猫娘的提供的脚本是否可行。谢谢:)

lyhyl commented 8 years ago

只有challenge request还有keep_alive2成功,不过好像不掉线……

wuansg commented 8 years ago

你弄好了没 @w282200695

wuansg commented 8 years ago

我也是广工的

wuansg commented 8 years ago

可以的话帮我一下

GGXGxchen commented 8 years ago

表示之前也会有掉线,ps | grep python 命令发现心跳包没有正常执行

kristar commented 8 years ago

ps | grep python drcom定时退出 pppoe的日志 [] pppoe: send heartbeat request [] pppoe: heartbeat response failed, retry [] pppoe: reset idx to 0x01 [] pppoe: send challenge request Traceback (most recent call last): File "/usr/bin/drcom", line 455, in main() File "/usr/bin/drcom", line 450, in main pppoe.send(s) File "/usr/bin/drcom", line 306, in send data, address = s.recv() File "/usr/bin/drcom", line 194, in recv data, address = self.s.recvfrom(1024) socket.timeout: timed out

wuansg commented 8 years ago

我也刷这个教程的,表示过一段时间就断

Zhicwan commented 8 years ago

有热心市民陈先生提供了可用的脚本。所以贴下源码,并关闭问题=_=

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import struct
import time
import sys
import random
import os
import hashlib

# CONFIG
server = '10.0.3.2'
pppoe_flag = '\x6b'
keep_alive2_flag = '\xdc'
# CONFIG_END

host_ip = server
IS_TEST = False
CONF = "/etc/drcom.conf"
DEBUG = False #log saves to file
if IS_TEST:
    CONF = ''
    DEBUG = True
    LOG_PATH = 'drcom_client.log'

def log(*args, **kwargs):
    s = ' '.join(args)
    if 'pkt' in kwargs and DEBUG == True:
        s += '\n\tpacket:' + kwargs['pkt'].encode('hex')
    print '[*] ', s
    if DEBUG:
        with open(LOG_PATH,'ab') as f:
            try:
                f.write(s)
                f.write('\n')
            except:
                f.write('FUCK WINDOWS' + '\n')
def dump(n):
    s = '%x' % n
    if len(s) & 1:
        s = '0' + s
    return s.decode('hex')

def gbk2utf8(string):
    try:
        import platform
        if platform.uname()[0] != 'Windows':
            return string.decode('gb2312').encode().decode()
        else:
            return string.decode('gb2312')
    except Exception as e:
        return 'You have witnessed too much...'

def gen_crc(data, encrypt_type):
    DRCOM_DIAL_EXT_PROTO_CRC_INIT = 20000711
    ret = ''
    if encrypt_type == 0:
        # 加密方式无
        return struct.pack('<I',DRCOM_DIAL_EXT_PROTO_CRC_INIT) + struct.pack('<I',126), False
    elif encrypt_type == 1:
        # 加密方式为 md5
        foo = hashlib.md5(data).digest()
        ret += foo[2]
        ret += foo[3]
        ret += foo[8]
        ret += foo[9]
        ret += foo[5]
        ret += foo[6]
        ret += foo[13]
        ret += foo[14]
        return ret, True
    elif encrypt_type == 2:
        # md4
        foo = hashlib.new('md4', data).digest()
        ret += foo[1]
        ret += foo[2]
        ret += foo[8]
        ret += foo[9]
        ret += foo[4]
        ret += foo[5]
        ret += foo[11]
        ret += foo[12]
        return ret, True
    elif encrypt_type == 3:
        # sha1
        foo = hashlib.sha1(data).digest()
        ret += foo[2]
        ret += foo[3]
        ret += foo[9]
        ret += foo[10]
        ret += foo[5]
        ret += foo[6]
        ret += foo[15]
        ret += foo[16]
        return ret, True

class Socket:
    def __init__(self, server, port=61440):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.s.bind(("0.0.0.0", 61440))
        log("open local port:" + str(port))
        log("DEBUG MODE:"+ str(DEBUG))
        self.server = server
        self.port = port
        self.s.settimeout(3)

    def send(self, data):
        self.s.sendto(data, (self.server, self.port))

    def recv(self):
        while True:
            data, address = self.s.recvfrom(1024)
            if data[0] == '\x4d':
                log('received message packet, dropped. message: ' + gbk2utf8(data[4:]))
                continue
            return data, address

    def get_socket(self):
        return self.s

    def sendto(self, data, *args):
        self.send(data)

    def recvfrom(self, *args):
        return self.recv()

class PPPOEHeartbeat:
    def __init__(self, num=1):
        self.count = num # 计数器
    def _make_challenge(self):
        data = '\x07'
        data += chr(self.count)
        data += '\x08\x00\x01\x00'
        data+= '\x00\x00'
        return data

    def _DrcomCRC32(self, data, init = 0):
      ret = init
      for i in range(len(data))[::4]:
          ret ^= struct.unpack('<I', data[i:i+4])[0]
          ret &= 0xFFFFFFFF
      return ret

    def _make_heartbeat(self, sip, challenge_seed, first=False):
        # DrcomDialExtProtoHeader - 5 bytes
        data = '\x07' # code
        data += chr(self.count) # id
        data += '\x60\x00' # length
        data += '\x03' # type
        data += '\x00' # uid length
        data += '\x00\x00\x00\x00\x00\x00' # mac
        data += sip # AuthHostIP
        if first:
            data += '\x00\x62\x00' + pppoe_flag # 非第一次则是 data += '\x00\x62\x00\x14'
        else:
            data += '\x00\x63\x00' + pppoe_flag
        data += challenge_seed # Challenge Seed

        #data += struct.pack('<I',20000711) # DRCOM_DIAL_EXT_PROTO_CRC_INIT
        #data += struct.pack('<I',126)
        #crc = (self._DrcomCRC32(data) * 19680126) & 0xFFFFFFFF
        encrypt_mode = struct.unpack('<I', challenge_seed)[0] & 3
        crc, foo = gen_crc(challenge_seed, encrypt_mode)
        data += crc
        if foo == False:
            crc2 = (self._DrcomCRC32(data) * 19680126) & 0xFFFFFFFF
            data = data[:-8] + struct.pack('<I', crc2) + '\x00\x00\x00\x00'
        # data += '\x7e\x00\x00\x00'
        #   data += '\x00\x00\x00\x7e'
        # - DrcomDialExtProtoHeader end -
        data += '\x00'*16 # ip1
        data += '\x00'*16 # ip2
        data += '\x00'*16 # ip3
        data += '\x00'*16 # ip4
        return data

    def send(self, s):
        while True:
            #1. challenge
            data = self._make_challenge()
            log('pppoe: send challenge request', pkt=data)
            s.send(data)
            data, address = s.recv()
            log('pppoe: received challenge response', pkt=data)

            self.count += 1
            self.count %= 0xFF

            #2. heartbeat
            seed = data[8:12]
            sip = data[12:16]
            if self.count != 2 and self.count != 1:
                data = self._make_heartbeat(sip=sip, challenge_seed=seed)
            else:
                data = self._make_heartbeat(sip=sip, challenge_seed=seed, first=True)
            log('pppoe: send heartbeat request', pkt=data)
            s.send(data)
            try:
                data, address = s.recv()
                log('pppoe: received heartbeat response', pkt=data)
                break
            except:
                log('pppoe: heartbeat response failed, retry')
                log('pppoe: reset idx to 0x01')
                self.count = 1
                continue

            self.count += 1
            self.count %= 0xFF

def keep_alive_package_builder(number,random,tail,type=1,first=False):
    data = '\x07'+ chr(number) + '\x28\x00\x0b' + chr(type)
    if first :
        data += '\x0f\x27'
    else:
        data += keep_alive2_flag + '\x02'
    data += '\x2f\x12' + '\x00' * 6
    data += tail
    #data += '\x00' * 4
    #data += struct.pack("!H",0xdc02)
    if type == 3:
        # print('type == 3')
        foo = ''.join([chr(int(i)) for i in '0.0.0.0'.split('.')]) # host_ip
        #CRC
        # edited on 2014/5/12, filled zeros to checksum
        # crc = packet_CRC(data+foo)
        encrypt_mode = struct.unpack('<I', tail)[0] & 3
        crc, val = gen_crc(data, encrypt_mode)
        #crc = '\x00' * 4
        #data += struct.pack("!I",crc) + foo + '\x00' * 8
        data += crc + foo + '\x00' * 8
    else: #packet type = 1
        data += '\x00' * 20
    return data

def keep_alive2(s, pppoe):
    tail = ''
    packet = ''
    svr = server

    ran = random.randint(0,0xFFFF)
    ran += random.randint(1,10)
    # 2014/10/15 add by latyas, maybe svr sends back a file packet
    svr_num = 0
    packet = keep_alive_package_builder(svr_num,dump(ran),'\x00'*4,1,True)
    while True:
        log('[keep-alive2] send1', pkt=packet)
        s.sendto(packet, (svr, 61440))
        data, address = s.recvfrom(1024)
        if data[0] == '\x07' and data[2] == '\x28':
            break
        elif data[0] == '\x07' and data[2] == '\x10':
            log('[keep-alive2] recv file, resending..')
            svr_num = svr_num + 1
            packet = keep_alive_package_builder(svr_num,dump(ran),'\x00'*4,svr_num,False)
        else:
            log('[keep-alive2] recv1/unexpected', pkt=data)
    log('[keep-alive2] recv1', pkt=data)

    ran += random.randint(1,10)
    packet = keep_alive_package_builder(svr_num, dump(ran),'\x00'*4,1,False)
    log('[keep-alive2] send2', pkt=packet)
    s.sendto(packet, (svr, 61440))
    while True:
        data, address = s.recvfrom(1024)
        if data[0] == '\x07':
            svr_num = svr_num + 1
            break
        else:
            log('[keep-alive2] recv2/unexpected', pkt=data)
    log('[keep-alive2] recv2', pkt=data)
    tail = data[16:20]

    ran += random.randint(1,10)
    packet = keep_alive_package_builder(svr_num,dump(ran),tail,3,False)
    log('[keep-alive2] send3', pkt=packet)
    s.sendto(packet, (svr, 61440))
    while True:
        data, address = s.recvfrom(1024)
        if data[0] == '\x07':
            svr_num = svr_num + 1
            break
        else:
            log('[keep-alive2] recv3/unexpected', pkt=data)
    log('[keep-alive2] recv3', pkt=data)
    tail = data[16:20]
    log("[keep-alive2] keep-alive2 loop was in daemon.")

    i = svr_num
    while True:
        try:
            ran += random.randint(1,10)
            packet = keep_alive_package_builder(i,dump(ran),tail,1,False)
            log('[keep_alive2] send',str(i), pkt=packet)
            s.sendto(packet, (svr, 61440))
            data, address = s.recvfrom(1024)
            log('[keep_alive2] recv', pkt=data)
            tail = data[16:20]

            ran += random.randint(1,10)
            packet = keep_alive_package_builder(i+1,dump(ran),tail,3,False)
            s.sendto(packet, (svr, 61440))
            log('[keep_alive2] send',str(i+1), pkt=packet)
            data, address = s.recvfrom(1024)
            log('[keep_alive2] recv', pkt=data)
            tail = data[16:20]
            i = (i+2) % 0xFF
            time.sleep(10)
            #send pppoe heartbeat once
            #pppoe.send(s)
        except:
            pass

def daemon():
    with open('/var/run/drcom_p.pid','w') as f:
        f.write(str(os.getpid()))

def main():
    if not IS_TEST:
        daemon()
        execfile(CONF, globals())
    log('auth svr: ' + server)
    log('pppoe_flag: ' + pppoe_flag.encode('hex'))
    log('keep_alive2_flag: ' + keep_alive2_flag.encode('hex'))

    s = Socket(server)
    while True:
        pppoe = PPPOEHeartbeat(1)
 #       pppoe.send(s)
        keep_alive2(s, pppoe)

if __name__ == '__main__':
    main()
larry0442 commented 8 years ago

@w282200695 找了好久才发现你说的贴吧是工吧,试了一下,热心网友猫娘的脚本可行,

larry0442 commented 8 years ago

原来已经贴出来了啊,

dgeibi commented 8 years ago

我这里暂时没掉线。 热心市民陈先生改了这些:

12,13c12,13
< server = '172.30.1.80'
< pppoe_flag = '\x2a'
---
> server = '10.0.3.2'
> pppoe_flag = '\x6b'
100c100
<         # self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
---
>         self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
313c313
<             pppoe.send(s)
---
>             #pppoe.send(s)
332c332
<         pppoe.send(s)
---
>  #       pppoe.send(s)
ly0 commented 8 years ago

嘛,应该是pppoe_flag变了吧

dgeibi commented 8 years ago

pppoe_flag 没变。使用 https://github.com/drcoms/drcom-generic/blob/master/latest-pppoe.py 大概十分钟掉线一次。热心市民陈先生的修改版也是这样……


pppoe_flag 变了……

dgeibi commented 8 years ago

https://github.com/hazytint/gdut-drcom/tree/1107 可用

ly0 commented 8 years ago

心跳少了一个

GGXGxchen commented 8 years ago

socket.error: [Errno 125] Address already in use。这是什么情况

ly0 commented 8 years ago

@GGXGxchen 关掉你的客户端。。。