Exemple #1
0
def dhcp_server_start():
    # Don't start if DHCP is not to be used
    if not db.get('prefix_dhcp'):
        return

    # Stop DHCP daemon
    bash(DHCP_DAEMON + ' stop')
    # Remove previous configuration for this NCP
    db.del_from_file(DHCP_CONFIG, '\niface %s' % db.get('interior_ifname'), '\n}\n')
    # Add new configuration
    with open(DHCP_CONFIG, 'w') as file_:
        file_.write('\n')
        file_.write('iface ' + db.get('interior_ifname') + ' {\n')
        file_.write('\tclient-max-lease 1\n')
        file_.write('\tunicast ' + db.get('ncp_rloc') + '\n')
        file_.write('\trapid-commit yes\n')
        file_.write('\toption ntp-server ' + db.get('ncp_mleid') + '\n')
        file_.write('\toption dns-server ' + db.get('ncp_mleid') + '\n')
        file_.write('\tpreference 255\n')
        file_.write('\tclass {\n')
        file_.write('\t\tT1 0\n')
        file_.write('\t\tT2 0\n')
        file_.write('\t\tpreferred-lifetime 86400\n')
        file_.write('\t\tvalid-lifetime 86400\n')
        file_.write('\t\tpool ' + db.get('prefix') + '\n')
        file_.write('\t}\n')
        file_.write('}\n')
    # Allow for the file to be stored
    time.sleep(0.2)
    # Start DHCP daemon
    bash(DHCP_DAEMON + ' start')
Exemple #2
0
def _ifdown():
    ifname = db.get('interior_ifname')

    # Remove custom routing table
    db.del_from_file(
        '/etc/iproute2/rt_tables',
        '\n%s\t%s\n' % (BR_TABLE_NR, db.get('bridging_table')),
        '',
    )

    # Don't continue if the interface is already down
    idx = IPR.link_lookup(ifname=ifname, operstate='UP')
    if not idx:
        return
    # Delete traffic limits
    bash('tc qdisc del dev %s root handle 1: cbq avpkt 1000 bandwidth 12mbit' %
         ifname)

    # Delete custom rule
    IPR.rule(
        'delete',
        family=socket.AF_INET6,
        table=BR_TABLE_NR,
        priority=100,
        fwmark=int(db.get('bridging_mark')),
    )

    # Bring interior interface down
    logging.info('Bringing %s interface down.', ifname)
    try:
        IPR.link('set', index=db.get('interior_ifnumber'), state='down')
    except:
        logging.error('Exception bringing %s interface down.', ifname)
Exemple #3
0
def handle_nat64_masking(ext_addr, enable=True):
    '''Enable or disable one exterior IPv4 address in the NAT64 Pool 4'''
    global POOL4_ACTIVE

    # Don't allow IPv6 addresses here
    try:
        ipaddress.IPv4Address(ext_addr)
    except:
        return

    jool_action = 'add' if enable else 'remove'
    log_action = 'used' if enable else 'removed'

    # Only allow one address in the Pool 4
    if (enable and POOL4_ACTIVE) or (not enable and not POOL4_ACTIVE):
        logging.info('Unable to %s %s as stateful NAT64 masking address.',
                     jool_action, ext_addr)
        return

    params = (jool_action, ext_addr)
    bash('jool pool4 %s %s 61001-65535 --udp' % params)
    bash('jool pool4 %s %s 61001-65535 --icmp' % params)
    POOL4_ACTIVE = True

    logging.info('%s %s as stateful NAT64 masking address.', ext_addr,
                 log_action)
Exemple #4
0
def ncp_fw_update():
    '''
    Compare the NCP firmware with the one available in the 'ncp_fiwmare' folder 
    and update if needed
    '''

    # Find the DFU file that matches the required fw version
    dfu_file = None
    ver_num = kibra.__kinosver__.split(' v')[-1]
    for file_name in importlib_resources.contents(NCP_FW_FOLDER):
        if ver_num in file_name:
            # TODO: This relies on the file name, we could also check the file
            # contents to make sure
            dfu_file = file_name
            break
    if not dfu_file:
        logging.error('Required NCP firmware not present.')
        sys.exit()

    # Flash the NCP and re-enable it
    with importlib_resources.path(NCP_FW_FOLDER, dfu_file) as dfu_path:
        logging.warn('NCP will be updated with firmware v%s' % ver_num)
        try:
            dfu_file = kidfu.DfuFile(str(dfu_path))
            kifwu.dfu_find_and_flash(dfu_file, unattended=True)
            # TODO: Remove this when KiTools is fixed for a proper USB re-enumeration
            # Reset USB device in KTBRN1
            bash('sh -c "echo 0 > /sys/bus/usb/devices/6-1/authorized"')
            bash('sh -c "echo 1 > /sys/bus/usb/devices/6-1/authorized"')
        except Exception as exc:
            logging.error('Problem updating NCP firmware: %s' % exc)
            sys.exit()

    logging.info('NCP updated successfully.')
Exemple #5
0
def block_local_multicast(action, maddr):
    src = db.get('exterior_ipv6_ll')
    if action is 'I':
        logging.info('Blocking local traffic to %s' % maddr)
    elif action is 'D':
        logging.info('Unblocking local traffic to %s' % maddr)
    else:
        return
    bash('%s -%s INPUT -s %s -d %s -j DROP' % (IP6TF, action, src, maddr))
Exemple #6
0
    def kstop(self):
        if self.nat_enabled:
            # Disnable NAT
            logging.info('Disabling Border Agent NAT.')
            self.nat_enabled = False
            nat_start('D')

        # Disable service
        logging.info('Removing Avahi service.')
        bash('rm /etc/avahi/services/%s.service' % db.get('dongle_name'))
        bash('service avahi-daemon reload')
Exemple #7
0
def _nat_enable():
    global POOL4_ACTIVE

    _nat_disable()

    bash('/sbin/modprobe jool')
    POOL4_ACTIVE = False
    logging.info('NAT64 engine started.')

    bash('jool instance add --netfilter --pool6 64:ff9b::/96')
    logging.info('Prefix 64:ff9b::/96 added to NAT64 engine.')
Exemple #8
0
    def service_update(self):
        r_txt = '\t\t<txt-record>%s=%s</txt-record>'
        r_bin = '\t\t<txt-record value-format="binary-hex">%s=%s</txt-record>'

        try:
            records = get_records()
            hostname = socket.gethostname()
        except:
            logging.warning('Unable to get the mDNS records.')
            return
        # Compose the new service data
        snw = []
        snw.append('<?xml version="1.0" encoding="utf-8" standalone="no"?>')
        snw.append('<!DOCTYPE service-group SYSTEM "avahi-service.dtd">')
        snw.append('<service-group>')
        snw.append('\t<name>%s %s %s</name>' %
                   (db.get('dongle_name'), records['vn'], records['mn']))
        snw.append('\t<service>')
        snw.append('\t\t<type>_meshcop._udp</type>')
        snw.append('\t\t<host-name>%s.local</host-name>' % hostname)
        snw.append('\t\t<port>%d</port>' % db.get('exterior_port_mc'))
        snw.append(r_txt % ('rv', '1'))
        snw.append(r_txt % ('tv', '1.2.0'))
        snw.append(r_bin % ('sb', records['sb']))
        snw.append(r_txt % ('vn', records['vn']))
        snw.append(r_txt % ('mn', records['mn']))
        if 'nn' in records.keys():
            snw.append(r_txt % ('nn', records['nn']))
        if 'xp' in records.keys():
            snw.append(r_bin % ('xp', records['xp']))
        if 'sq' in records.keys():
            snw.append(r_bin % ('sq', records['sq']))
        if 'bb' in records.keys():
            snw.append(r_bin % ('bb', records['bb']))
        snw.append('\t</service>')
        snw.append('</service-group>\n')
        snw = '\n'.join(snw)

        # Load the previous service file, or create it
        pathlib.Path(MDNS_SERVICES).mkdir(parents=True, exist_ok=True)
        service_file = '%s/%s.service' % (MDNS_SERVICES, db.get('dongle_name'))
        file_name = pathlib.Path(service_file)
        file_name.touch(exist_ok=True)

        with open(str(service_file), 'r') as file_:
            sod = file_.read()

        # Only restart service if something changed
        if snw != sod:
            with open(str(file_name), 'w') as file_:
                file_.write(snw)
            bash('service avahi-daemon reload')
            logging.info('mDNS service updated.')
Exemple #9
0
def handle_diag(action, ncp_rloc):
    '''handle_diag('I') -> Insert the rules
    diagNetfilter('D') -> Delete the rules'''
    if action is 'I':
        logging.info('Redirecting MM port traffic to interior interface.')
    elif action is 'D':
        logging.info('Deleting ip6tables diagnostics rules.')
    else:
        return

    bash(
        '%s -%s OUTPUT -o lo -d %s -p udp --dport %s -j MARK --set-mark "%s"' %
        (IP6TM, action, ncp_rloc, DEFS.PORT_MM, db.get('bridging_mark')))
Exemple #10
0
def dhcp_server_stop():
    # Don't stop if DHCP is not to be used
    if not db.get('prefix_dhcp'):
        return
        
    # Stop DHCP daemon
    bash(DHCP_DAEMON + ' stop')
    # Remove previous configuration for this NCP
    db.del_from_file(DHCP_CONFIG, '\niface %s' % db.get('interior_ifname'), '\n}\n')
    # Allow for the file to be stored
    time.sleep(0.2)

    # Start DHCP daemon
    bash(DHCP_DAEMON + ' start')
Exemple #11
0
    def kstop(self):
        # Don't stop if DHCP is not to be used
        if not db.get('prefix_dhcp'):
            return

        #TODO: https://www.claudiokuenzler.com/blog/694/get-unbount-dns-lookups-resolution-working-ubuntu-16.04-xenial
        # Stop DNS daemon
        bash('service %s stop' % DNS_DAEMON)
        # Remove previous configuration for this dongle
        db.del_from_file(DNS_CONFIG, '\nserver:',
                         '\n    dns64-synthall: yes\n')
        # Allow for the file to be stored
        sleep(0.2)
        # Start DNS daemon
        bash('service %s start' % DNS_DAEMON)
Exemple #12
0
    def kstop(self):
        # Don't stop if DHCP is not to be used
        if not db.get('prefix_dhcp'):
            return

        # Stop DHCP daemon
        bash(DHCP_DAEMON + ' stop')
        # Remove previous configuration for this dongle
        db.del_from_file(DHCP_CONFIG, '\niface %s' % db.get('interior_ifname'),
                         '\n}\n')
        # Allow for the file to be stored
        sleep(0.2)
        # Remove route
        dongle_route_disable(db.get('prefix'))
        # Start DHCP daemon
        bash(DHCP_DAEMON + ' start')
Exemple #13
0
    def kstart(self):
        # Don't start if DHCP is not to be used
        if not db.get('prefix_dhcp'):
            return

        # Stop DNS daemon
        bash('service %s stop' % DNS_DAEMON)
        # Remove previous configuration
        db.del_from_file(DNS_CONFIG, '\nserver:',
                         '\n    dns64-synthall: yes\n')
        # Add new configuration
        with open(DNS_CONFIG, 'w') as file_:
            file_.write('\nserver:')
            file_.write('\n    interface: %s' % db.get('dongle_mleid'))
            file_.write('\n    access-control: ::/0 allow')
            file_.write('\n    module-config: "dns64 validator iterator"')
            file_.write('\n    dns64-prefix: 64:ff9b::/96')
            file_.write('\n    dns64-synthall: yes\n')
        # Allow for the file to be stored
        sleep(0.2)
        # Start DNS daemon
        bash('service %s start' % DNS_DAEMON)
Exemple #14
0
    def kstart(self):
        # Don't start if DHCP is not to be used
        if not db.get('prefix_dhcp'):
            return

        # Stop DHCP daemon
        bash(DHCP_DAEMON + ' stop')
        # Remove previous configuration for this dongle
        db.del_from_file(DHCP_CONFIG, '\niface %s' % db.get('interior_ifname'),
                         '\n}\n')
        # Add new configuration
        with open(DHCP_CONFIG, 'w') as file_:
            file_.write('\n')
            file_.write('iface ' + db.get('interior_ifname') + ' {\n')
            file_.write('\tclient-max-lease 1\n')
            file_.write('\tunicast ' + db.get('dongle_rloc') + '\n')
            file_.write('\trapid-commit yes\n')
            # file_.write('\toption 224 address ' + db.get('dongle_rloc') + '\n') # CoAP RD
            #file_.write('\toption 56 duid ' + ntp_server_opt(db.get('dongle_rloc')) + '\n')
            file_.write('\toption ntp-server ' + db.get('dongle_mleid') + '\n')
            file_.write('\toption dns-server ' + db.get('dongle_mleid') + '\n')
            file_.write('\tpreference 255\n')
            file_.write('\tclass {\n')
            file_.write('\t\tT1 0\n')
            file_.write('\t\tT2 0\n')
            file_.write('\t\tpreferred-lifetime 1500\n')
            file_.write('\t\tvalid-lifetime 1800\n')
            file_.write('\t\tpool ' + db.get('prefix') + '\n')
            file_.write('\t}\n')
            #file_.write('\tclient duid ' + db.get('dongle_mac') + ' {\n')
            #file_.write('\t\taddress ' + db.get('dhcp_server') + '\n')
            # file_.write('\t}\n')
            file_.write('}\n')
        # Allow for the file to be stored
        sleep(0.2)
        # Start DHCP daemon
        bash(DHCP_DAEMON + ' start')
Exemple #15
0
def handle_bagent_fwd(ext_addr, int_addr, enable=True):
    '''Enable or disable Border Agent traffic forwarding between one exterior 
    address and the NCP, using Jool for IPv6 and iptables for IPv6'''

    # Get parameters
    try:
        ipaddress.IPv4Address(ext_addr)
        is_ipv4 = True
    except:
        is_ipv4 = False
    jool_action = 'add' if enable else 'remove'
    ipt_action = 'I' if enable else 'D'
    ipt_bin = IPTM if is_ipv4 else IP6TM
    ext_ifame = db.get('exterior_ifname')
    ext_port = db.get('exterior_port_mc')
    int_port = db.get('bagent_port')
    brdg_mark = db.get('bridging_mark')

    # NAT 4 -> 6
    if is_ipv4:
        params = (jool_action, ext_addr, ext_port, int_addr, int_port)
        bash('jool bib %s %s#%s %s#%s --udp' % params)
    # NAT 6 -> 6
    else:
        params = (IP6TN, ipt_action, ext_ifame, ext_addr, ext_port, int_addr,
                  int_port)
        bash(
            '%s -%s PREROUTING -i %s -d %s -p udp --dport %d -j DNAT --to [%s]:%d'
            % params)

    # Mark MC packets before they are translated,
    # so they are not consumed by Linux but by the NCP
    params = (ipt_bin, ipt_action, ext_ifame, ext_addr, ext_port, brdg_mark)
    bash(
        '%s -%s PREROUTING -i %s -d %s -p udp --dport %d -j MARK --set-mark %s'
        % params)

    logging.info('Border Agent forwarding updated.')
Exemple #16
0
def _handle_ipv4(action):
    '''
    Block most of the exterior traffic
     _handle_ipv4('A')  --> Add the rules
     _handle_ipv4('D')  --> Delete the rules
    '''
    if action == 'A':
        # This should not be needed if KiBRA was closed correctly
        bash('iptables -F -t mangle')

    params = (IPTF, action, db.get('exterior_ifname'))
    bash('%s -%s INPUT -i %s -p icmp -j ACCEPT' % (params))
    bash('%s -%s INPUT -i %s -p udp --dport mdns -j ACCEPT' % (params))
    bash('%s -%s INPUT -i %s -p udp --dport dhcpv6-client -j ACCEPT' %
         (params))
    bash('%s -%s INPUT -i %s -m state --state ESTABLISHED,RELATED -j ACCEPT' %
         (params))
    bash('%s -%s INPUT -i %s -j DROP' % (params))
Exemple #17
0
def handle_ipv6(action):
    '''handle_ipv6('A')  --> Add the rules
    handle_ipv6('D')  --> Delete the rules'''

    if action is 'A':
        logging.info('Adding ip6tables general rules.')
        # This should not be needed if KiBRA was closed correctly
        bash('ip6tables -F -t mangle')
        bash('ip6tables -F -t nat')
        bash('ip6tables -F -t filter')
    elif action is 'D':
        logging.info('Deleting ip6tables general rules.')
    else:
        return

    interior_ifname = db.get('interior_ifname')
    prefix = db.get('prefix')

    # INPUT
    # Disallow incoming multicast ping requests
    bash(
        '%s -%s INPUT -i %s -d ff00::/8 -p icmpv6 --icmpv6-type echo-request -j DROP'
        % (IP6TF, action, db.get('exterior_ifname')))

    # OUTPUT
    # Prevent fragmentation
    bash('%s -%s OUTPUT -o %s -m length --length 1281:0xffff -j REJECT' %
         (IP6TF, action, interior_ifname))
    # Allow some ICMPv6 traffic towards the Thread interface
    bash(
        '%s -%s OUTPUT -o %s -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT'
        % (IP6TF, action, interior_ifname))
    bash('%s -%s OUTPUT -o %s -p icmpv6 --icmpv6-type echo-request -j ACCEPT' %
         (IP6TF, action, interior_ifname))
    # Allow CoAP
    bash('%s -%s OUTPUT -o %s -p udp --sport %s -j ACCEPT' %
         (IP6TF, action, interior_ifname, DEFS.PORT_COAP))
    bash('%s -%s OUTPUT -o %s -p udp --dport %s -j ACCEPT' %
         (IP6TF, action, interior_ifname, DEFS.PORT_COAP))
    bash('%s -%s OUTPUT -o %s -p udp --sport %s -j ACCEPT' %
         (IP6TF, action, interior_ifname, DEFS.PORT_MM))
    bash('%s -%s OUTPUT -o %s -p udp --dport %s -j ACCEPT' %
         (IP6TF, action, interior_ifname, DEFS.PORT_MM))
    # Allow DHCPv6 server
    bash('%s -%s OUTPUT -o %s -p udp --dport dhcpv6-client -j ACCEPT' %
         (IP6TF, action, interior_ifname))
    # Allow NTP server
    bash('%s -%s OUTPUT -o %s -p udp --sport 123 -j ACCEPT' %
         (IP6TF, action, interior_ifname))
    # Allow DNS server
    bash('%s -%s OUTPUT -o %s -p udp --sport 53 -j ACCEPT' %
         (IP6TF, action, interior_ifname))
    # Block all other outgoing traffic to the Thread interface
    bash('%s -%s OUTPUT -o %s -j DROP' % (IP6TF, action, interior_ifname))
    # Block Thread traffic on the Ethernet interface
    if not db.get('prefix_dua'):
        bash('%s -%s OUTPUT -o %s -p ipv6 -d %s -j DROP' %
             (IP6TF, action, db.get('exterior_ifname'), prefix))

    # FORWARD
    # Prevent fragmentation
    bash('%s -%s FORWARD -o %s -m length --length 1281:0xffff -j REJECT' %
         (IP6TF, action, interior_ifname))
    # Forward marked packets for PBR
    bash('%s -%s FORWARD -m mark --mark "%s" -j ACCEPT' %
         (IP6TF, action, db.get('bridging_mark')))
    # Reflective session state (9.2.7_13)
    bash('%s -%s FORWARD -p udp -m state --state ESTABLISHED -j ACCEPT' %
         (IP6TF, action))
    bash(
        '%s -%s FORWARD -p icmpv6 -m state --state ESTABLISHED,RELATED -j ACCEPT'
        % (IP6TF, action))
    # Forward all multicast (filtering is made by mcrouter)
    bash('%s -%s FORWARD -d ff00::/8 -j ACCEPT' % (IP6TF, action))
    # Forward announced prefix
    bash('%s -%s FORWARD -d %s -j ACCEPT' % (IP6TF, action, prefix))
    bash('%s -%s FORWARD -s %s -j ACCEPT' % (IP6TF, action, prefix))
    # Block all other forwarding
    bash('%s -%s FORWARD -j DROP' % (IP6TF, action))
Exemple #18
0
 def kstop(self):
     # Disable service
     logging.info('Removing Avahi service.')
     bash('rm /etc/avahi/services/%s.service' % db.get('ncp_name'))
     bash('service avahi-daemon restart')
Exemple #19
0
def _nat_disable():
    bash('/sbin/modprobe -r jool')
    logging.info('NAT64 engine stopped.')
Exemple #20
0
def _ifup():
    # Make sure forwarding is enabled
    bash('echo 1 > /proc/sys/net/ipv4/conf/all/forwarding')
    bash('echo 1 > /proc/sys/net/ipv6/conf/all/forwarding')
    logging.info('Forwarding has been enabled.')

    # Disable duplicate address detection for the interior interface
    bash('echo 0 > /proc/sys/net/ipv6/conf/%s/accept_dad' %
         db.get('interior_ifname'))
    logging.info('DAD has been disabled for %s.', db.get('interior_ifname'))

    # Enable a bigger number of multicast groups
    # https://www.kernel.org/doc/Documentation/sysctl/net.txt
    bash('echo 65536 > /proc/sys/net/core/optmem_max')

    # Bring interior interface up
    idx = db.get('interior_ifnumber')
    # First bring it down to remove old invalid addresses
    IPR.link('set', index=idx, state='down')
    IPR.link('set', index=idx, state='up', txqlen=5000)

    # Add inside IPv6 addresses
    logging.info('Configuring interior interface %s with address %s.',
                 db.get('interior_ifname'), db.get('dongle_rloc'))
    IPR.addr('add', index=idx, address=db.get('dongle_rloc'), prefixlen=64)
    logging.info('Configuring interior interface %s with address %s.',
                 db.get('interior_ifname'), db.get('dongle_mleid'))
    IPR.addr('add', index=idx, address=db.get('dongle_mleid'), prefixlen=64)

    # Add dongle neighbour
    IPR.neigh('replace',
              family=AF_INET6,
              dst=db.get('dongle_ll'),
              lladdr=db.get('dongle_mac'),
              ifindex=idx,
              nud='permanent')
    IPR.neigh('replace',
              family=AF_INET6,
              dst=db.get('dongle_rloc'),
              lladdr=db.get('dongle_mac'),
              ifindex=idx,
              nud='permanent')
    IPR.neigh('replace',
              family=AF_INET6,
              dst=db.get('dongle_mleid'),
              lladdr=db.get('dongle_mac'),
              ifindex=idx,
              nud='permanent')

    # Add custom routing table
    rt_tables = _get_rt_tables()
    if not db.get('bridging_table') in rt_tables:
        _rt_add_table(db.get('bridging_table'), BR_TABLE_NR)

    # Add default route to custom table
    IPR.route('replace',
              family=AF_INET6,
              dst='default',
              table=BR_TABLE_NR,
              oif=idx)

    rules = IPR.get_rules(family=AF_INET6)

    # Make marked packets use the custom table
    # TODO: different priorities for different dongles
    if str(db.get('bridging_mark')) not in str(rules):
        IPR.rule('add',
                 family=AF_INET6,
                 table=BR_TABLE_NR,
                 priority=100,
                 fwmark=int(db.get('bridging_mark')))

    # Set priority of local table lower than custom table's
    for rule in rules:
        if rule.get('table') == rt_tables.get('local'):
            IPR.rule('delete',
                     family=AF_INET6,
                     table=rule.get('table'),
                     priority=rule.get_attr('FRA_PRIORITY') or 0)
    IPR.rule('add',
             family=AF_INET6,
             table=rt_tables.get('local'),
             priority=1000)
    '''
Exemple #21
0
def nat_start(action):
    '''
    natMdnsStart I -> Insert the rules
    natMdnsStart D -> Delete the rules
    '''
    # NAT 4 -> 6
    if db.has_keys(['exterior_ipv4']):
        if action == 'I':
            bash('jool bib add %s#%s %s#%s --udp' %
                 (db.get('exterior_ipv4'), str(db.get('exterior_port_mc')),
                  db.get('dongle_rloc'), str(db.get('bagent_port'))))
        else:
            bash('jool bib remove %s#%s %s#%s --udp' %
                 (db.get('exterior_ipv4'), str(db.get('exterior_port_mc')),
                  db.get('dongle_rloc'), str(db.get('bagent_port'))))
        # Mark MC packets before they are translated, so they are not consumed by Linux but by the dongle
        # Flush old rules first
        bash('iptables -F -t mangle')
        bash(
            'iptables -w -t mangle -%s PREROUTING -i %s -d %s -p udp --dport %d -j MARK --set-mark %s'
            % (action, db.get('exterior_ifname'), db.get('exterior_ipv4'),
               db.get('exterior_port_mc'), db.get('bridging_mark')))
    # NAT 6 -> 6
    if db.has_keys(['exterior_ipv6_ll']):
        bash(
            'ip6tables -w -t nat -%s PREROUTING -i %s -d %s -p udp --dport %d -j DNAT --to [%s]:%d'
            % (action, db.get('exterior_ifname'), db.get('exterior_ipv6_ll'),
               db.get('exterior_port_mc'), db.get('dongle_rloc'),
               db.get('bagent_port')))
        bash(
            'ip6tables -w -t nat -%s POSTROUTING -o %s -s %s -p udp --sport %d -j SNAT --to [%s]:%d'
            % (action, db.get('exterior_ifname'), db.get('dongle_rloc'),
               db.get('bagent_port'), db.get('exterior_ipv6_ll'),
               db.get('exterior_port_mc')))
        bash(
            'ip6tables -w -t mangle -%s PREROUTING -i %s -d %s -p udp --dport %d -j MARK --set-mark %s'
            % (action, db.get('exterior_ifname'), db.get('exterior_ipv6_ll'),
               db.get('exterior_port_mc'), db.get('bridging_mark')))
Exemple #22
0
def netmap(old_dst, new_dst):
    logging.info('Redirecting traffic from %s to %s.' % (old_dst, new_dst))
    # TODO: make this work properly
    bash('ip6tables -t nat -A PREROUTING -i %s -d %s -j NETMAP --to %s' %
         (db.get('interior_ifname'), old_dst, new_dst))
Exemple #23
0
def new_external_addresses():
    '''Be notified about new addresses in the external interface'''

    # Restart Avahi to make it use the new addresses
    logging.info('Restarting Avahi service.')
    bash('service avahi-daemon restart')
Exemple #24
0
    def do_GET(self):
        binary = False
        if self.path == '/':
            self.path = '/index.html'
        file_path = '%s%s' % (PUBLIC_DIR, self.path.replace('/assets', ''))
        mime_type = 'text/json'

        try:
            # Parse URL fields
            req = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)

            # Different actions
            data = 'OK'
            if self.path == '/logs':
                # TODO: fancy colourfull autorefresh logs page
                with open(db.LOG_FILE, 'r') as file_:
                    data = file_.read()
                mime_type = 'text/plain'
            elif self.path == '/db/cfg':
                data = db.dump()
            elif self.path == '/db/nodes':
                data = json.dumps(DIAGS_DB, indent=2)
            elif self.path == '/db/leases':
                data = json.dumps(_get_leases(), indent=2)
            elif os.path.isfile(file_path):
                if self.path.endswith(".html"):
                    mime_type = 'text/html'
                if self.path.endswith(".png"):
                    mime_type = 'image/png'
                    binary = True
                if self.path.endswith(".js"):
                    mime_type = 'application/javascript'
                if self.path.endswith(".css"):
                    mime_type = 'text/css'
                with open(file_path, 'rb' if binary else 'r') as file_:
                    data = file_.read()
            elif kibra.__harness__ and self.path.startswith('/api'):
                for key in req.keys():
                    if not key in db.modifiable_keys():
                        self.send_response(http.HTTPStatus.BAD_REQUEST)
                        return
                # Apply incoming changes
                modif_keys = set()
                for key, value in req.items():
                    if str(db.get(key)) != value[0]:
                        db.set(key, value[0])
                        modif_keys.add(key)
                # Special actions
                if not set(['mlr_timeout', 'rereg_delay'
                            ]).isdisjoint(modif_keys):
                    bbr_dataset_update()
            elif kibra.__harness__ and self.path.startswith('/ksh'):
                cmd = req.get('c', None)
                if cmd:
                    data = '\n'.join(send_cmd(cmd[0]))
                else:
                    return
            elif kibra.__harness__ and self.path.startswith('/ping'):
                dst = req.get('dst', ['0100::'])[0]
                size = req.get('sz', ['0'])[0]
                hl = req.get('hl', ['255'])[0]
                iface = db.get('exterior_ifname')
                port = req.get('port', [''])[0]
                tout = req.get('tout', ['0'])[0]
                if port:
                    # UDP
                    cmd = 'nping -6 --udp'
                    cmd += ' --source-port %s --dest-port %s' % (port, port)
                    cmd += ' --no-capture --count 1'
                    cmd += ' --interface %s' % iface
                    cmd += ' --dest-ip %s' % dst
                    cmd += ' --source-mac %s' % db.get('exterior_mac')
                    # TODO: https://en.wikipedia.org/wiki/Multicast_address#Ethernet
                    cmd += ' --dest-mac ff:ff:ff:ff:ff:ff'
                    cmd += ' --hop-limit %s' % hl
                    # TODO: use DUA as source
                    cmd += ' --source-ip %s' % db.get('exterior_ipv6_ll')
                    cmd += ' --data-length %s' % size
                else:
                    # ICMP
                    cmd = 'ping -6 -c1'
                    cmd += ' -W%s -s%s -t%s -I%s %s' % (tout, size, hl, iface,
                                                        dst)
                try:
                    data = bash(cmd)
                except Exception as e:
                    logging.error(e)
                    data = 'ping error'
            elif kibra.__harness__ and self.path.startswith('/radvd'):
                off = req.get('off')
                backhaul = req.get('bh')
                domain = req.get('dm')
                if off:
                    bash('service radvd stop')
                elif backhaul and domain:
                    if not db.get('exterior_ifname'):
                        NETWORK.set_ext_iface()
                    with open('/etc/radvd.conf', 'w') as file_:
                        file_.write('interface %s {\n' %
                                    db.get('exterior_ifname'))
                        file_.write('  AdvSendAdvert on;\n')
                        file_.write('  prefix %s { AdvAutonomous on; };\n' %
                                    backhaul[0])
                        file_.write('  prefix %s { AdvAutonomous off; };\n' %
                                    domain[0])
                        file_.write('};\n')
                    bash('echo 1 > /proc/sys/net/ipv6/conf/all/forwarding')
                    bash('ip -6 neighbor flush all')
                    bash('service radvd restart')
                else:
                    return
            elif kibra.__harness__ and self.path.startswith('/mdnsqry'):
                bash('dig -p 5353 @ff02::fb _meshcop._udp.local ptr')
            elif kibra.__harness__ and self.path.startswith('/duastatus'):
                db.set('dua_next_status', req.get('sta')[0])
                db.set('dua_next_status_eid', req.get('eid')[0])
            elif kibra.__harness__ and self.path.startswith('/mlrstatus'):
                db.set('mlr_next_status', req.get('sta')[0])
            elif kibra.__harness__ and self.path.startswith('/sendudp'):
                NETWORK.send_udp(
                    req.get('dst')[0],
                    req.get('prt')[0],
                    req.get('pld')[0])
            elif kibra.__harness__ and self.path.startswith('/ipneigh'):
                bash(req.get('cmd'))
            else:
                self.send_response(http.HTTPStatus.NOT_FOUND)
                return
        except:
            self.send_response(http.HTTPStatus.INTERNAL_SERVER_ERROR)
            return

        self.send_response(http.HTTPStatus.OK)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Content-type', mime_type)
        self.end_headers()
        if not binary:
            data = data.encode()
        self.wfile.write(data)
Exemple #25
0
def _nat_disable():
    if db.has_keys(['exterior_ipv4']):
        bash('jool pool4 remove --udp %s' %
             db.get('exterior_ipv4'))
        bash('jool pool4 remove --icmp %s' % db.get('exterior_ipv4'))
    bash('/sbin/modprobe -r jool')
Exemple #26
0
def _nat_enable():
    bash('/sbin/modprobe jool')
    if 'default' not in str(bash('jool instance display')):
        bash('jool instance add --netfilter --pool6 64:ff9b::/96')
        bash('jool global update logging-session true')
        bash('jool global update logging-bib true')
    logging.info('Prefix 64:ff9b::/96 added to NAT64 engine.')
    bash('jool pool4 add --udp %s' % db.get('exterior_ipv4'))
    bash('jool pool4 add --icmp %s' % db.get('exterior_ipv4'))
    logging.info('%s used as stateful NAT64 masking address.',
                 db.get('exterior_ipv4'))
Exemple #27
0
def _ifup():
    # For the Thread Harness, remove old neighbors
    if kibra.__harness__:
        bash('ip -6 neigh flush all')

    ifname = db.get('interior_ifname')

    # Make sure forwarding is enabled
    bash('echo 1 > /proc/sys/net/ipv4/conf/all/forwarding')
    bash('echo 1 > /proc/sys/net/ipv6/conf/all/forwarding')
    logging.info('Forwarding has been enabled.')

    # Disable duplicate address detection for the interior interface
    bash('echo 0 > /proc/sys/net/ipv6/conf/%s/accept_dad' % ifname)
    logging.info('DAD has been disabled for %s.', ifname)

    # Enable a bigger number of multicast groups
    # https://www.kernel.org/doc/Documentation/sysctl/net.txt
    bash('echo 65536 > /proc/sys/net/core/optmem_max')

    # Bring interior interface up
    idx = db.get('interior_ifnumber')
    # First bring it down to remove old invalid addresses
    IPR.link('set', index=idx, state='down')
    IPR.link('set', index=idx, state='up', txqlen=5000)

    # Add custom routing table
    rt_tables = _get_rt_tables()
    if not db.get('bridging_table') in rt_tables:
        _rt_add_table(db.get('bridging_table'), BR_TABLE_NR)

    # Add default route to custom table
    IPR.route('replace',
              family=socket.AF_INET6,
              dst='default',
              table=BR_TABLE_NR,
              oif=idx)

    rules = IPR.get_rules(family=socket.AF_INET6)

    # Make marked packets use the custom table
    # TODO: different priorities for different NCPs
    if str(db.get('bridging_mark')) not in str(rules):
        IPR.rule(
            'add',
            family=socket.AF_INET6,
            table=BR_TABLE_NR,
            priority=100,
            fwmark=int(db.get('bridging_mark')),
        )

    # Set priority of local table lower than custom table's
    for rule in rules:
        if rule.get('table') == rt_tables.get('local'):
            IPR.rule(
                'delete',
                family=socket.AF_INET6,
                table=rule.get('table'),
                priority=rule.get_attr('FRA_PRIORITY') or 0,
            )
    IPR.rule('add',
             family=socket.AF_INET6,
             table=rt_tables.get('local'),
             priority=1000)

    # Rate limit traffic to the interface, 125 kbps (maximum data rate in the
    # air)
    logging.info('Traffic rate limit established to %s on interface %s.',
                 '125 kbps', ifname)
    bash('tc qdisc add dev %s root handle 1: cbq avpkt 1000 bandwidth 12mbit' %
         ifname)
    bash(
        'tc class add dev %s parent 1: classid 1:1 cbq rate 125kbit allot 1500 prio 5 bounded isolated'
        % ifname)
    bash(
        'tc filter add dev %s parent 1: protocol ipv6 prio 16 u32 match ip6 dst ::/0 flowid 1:1'
        % ifname)