Ejemplo n.º 1
0
def _parse_slp_packet(packet, peer, rsps, xidmap):
    parsed = _parse_slp_header(packet)
    if not parsed:
        return
    addr = peer[0]
    if '%' in addr:
        addr = addr[:addr.index('%')]
    mac = None
    if addr not in neighutil.neightable:
        neighutil.update_neigh()
    if addr in neighutil.neightable:
        identifier = neighutil.neightable[addr]
        mac = identifier
    else:
        identifier = addr
    if (identifier, parsed['xid']) in rsps:
        # avoid obviously duplicate entries
        parsed = rsps[(identifier, parsed['xid'])]
    else:
        rsps[(identifier, parsed['xid'])] = parsed
    if mac and 'hwaddr' not in parsed:
        parsed['hwaddr'] = mac
    if parsed['xid'] in xidmap:
        parsed['services'] = [xidmap[parsed['xid']]]
    if 'addresses' in parsed:
        if peer not in parsed['addresses']:
            parsed['addresses'].append(peer)
    else:
        parsed['addresses'] = [peer]
    if parsed['function'] == 2:  # A service reply
        _parse_SrvRply(parsed)
Ejemplo n.º 2
0
def active_scan(handler, protocol=None):
    known_peers = set([])
    for scanned in scan():
        for addr in scanned['addresses']:
            ip = addr[0].partition('%')[0]  # discard scope if present
            if ip not in neighutil.neightable:
                neighutil.update_neigh()
            if ip not in neighutil.neightable:
                continue
            if addr in known_peers:
                break
            known_peers.add(addr)
        else:
            scanned['protocol'] = protocol
            handler(scanned)
Ejemplo n.º 3
0
def snoop(handler, protocol=None):
    """Watch for SLP activity

    handler will be called with a dictionary of relevant attributes

    :param handler:
    :return:
    """
    tracelog = log.Logger('trace')
    try:
        active_scan(handler, protocol)
    except Exception as e:
        tracelog.log(traceback.format_exc(),
                     ltype=log.DataTypes.event,
                     event=log.Events.stacktrace)
    net = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    net.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
    slpg = socket.inet_pton(socket.AF_INET6, 'ff01::123')
    slpg2 = socket.inet_pton(socket.AF_INET6, 'ff02::123')
    for i6idx in util.list_interface_indexes():
        mreq = slpg + struct.pack('=I', i6idx)
        net.setsockopt(IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
        mreq = slpg2 + struct.pack('=I', i6idx)
        net.setsockopt(IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
    net4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    net.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    net4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    for i4 in util.list_ips():
        if 'broadcast' not in i4:
            continue
        slpmcast = socket.inet_aton('239.255.255.253') + \
            socket.inet_aton(i4['addr'])
        try:
            net4.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
                            slpmcast)
        except socket.error as e:
            if e.errno != 98:
                raise
            # socket in use can occur when aliased ipv4 are encountered
    net.bind(('', 427))
    net4.bind(('', 427))

    while True:
        try:
            newmacs = set([])
            r, _, _ = select.select((net, net4), (), (), 60)
            # clear known_peers and peerbymacaddress
            # to avoid stale info getting in...
            # rely upon the select(0.2) to catch rapid fire and aggregate ip
            # addresses that come close together
            # calling code needs to understand deeper context, as snoop
            # will now yield dupe info over time
            known_peers = set([])
            peerbymacaddress = {}
            while r:
                for s in r:
                    (rsp, peer) = s.recvfrom(9000)
                    ip = peer[0].partition('%')[0]
                    if peer in known_peers:
                        continue
                    if ip not in neighutil.neightable:
                        neighutil.update_neigh()
                    if ip not in neighutil.neightable:
                        continue
                    known_peers.add(peer)
                    mac = neighutil.neightable[ip]
                    if mac in peerbymacaddress:
                        peerbymacaddress[mac]['addresses'].append(peer)
                    else:
                        q = query_srvtypes(peer)
                        if not q or not q[0]:
                            # SLP might have started and not ready yet
                            # ignore for now
                            known_peers.discard(peer)
                            continue
                        # we want to prioritize the very well known services
                        svcs = []
                        for svc in q:
                            if svc in _slp_services:
                                svcs.insert(0, svc)
                            else:
                                svcs.append(svc)
                        peerbymacaddress[mac] = {
                            'services': svcs,
                            'addresses': [peer],
                        }
                    newmacs.add(mac)
                r, _, _ = select.select((net, net4), (), (), 0.2)
            for mac in newmacs:
                peerbymacaddress[mac]['xid'] = 1
                _add_attributes(peerbymacaddress[mac])
                peerbymacaddress[mac]['hwaddr'] = mac
                peerbymacaddress[mac]['protocol'] = protocol
                for srvurl in peerbymacaddress[mac].get('urls', ()):
                    if len(srvurl) > 4:
                        srvurl = srvurl[:-3]
                    if srvurl.endswith('://Athena:'):
                        continue
                if 'service:ipmi' in peerbymacaddress[mac]['services']:
                    continue
                if 'service:lightttpd' in peerbymacaddress[mac]['services']:
                    currinf = peerbymacaddress[mac]
                    curratt = currinf.get('attributes', {})
                    if curratt.get('System-Manufacturing',
                                   [None])[0] == 'Lenovo' and curratt.get(
                                       'type',
                                       [None])[0] == 'LenovoThinkServer':
                        peerbymacaddress[mac]['services'] = [
                            'service:lenovo-tsm'
                        ]
                    else:
                        continue
                handler(peerbymacaddress[mac])
        except Exception as e:
            tracelog.log(traceback.format_exc(),
                         ltype=log.DataTypes.event,
                         event=log.Events.stacktrace)
Ejemplo n.º 4
0
def snoop(handler, byehandler=None, protocol=None, uuidlookup=None):
    """Watch for SSDP notify messages

    The handler shall be called on any service coming online.
    byehandler is called whenever a system advertises that it is departing.
    If no byehandler is specified, byebye messages are ignored.  The handler is
    given (as possible), the mac address, a list of viable sockaddrs to reference
    the peer, and the notification type (e.g.
    'urn:dmtf-org:service:redfish-rest:1'

    :param handler:  A handler for online notifications from network
    :param byehandler: Optional handler for devices going off the network
    """
    # Normally, I like using v6/v4 agnostic socket. However, since we are
    # dabbling in multicast wizardry here, such sockets can cause big problems,
    # so we will have two distinct sockets
    tracelog = log.Logger('trace')
    known_peers = set([])
    net6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
    for ifidx in util.list_interface_indexes():
        v6grp = ssdp6mcast + struct.pack('=I', ifidx)
        net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, v6grp)
    net6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    net4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    for i4 in util.list_ips():
        ssdp4mcast = socket.inet_pton(socket.AF_INET, mcastv4addr) + \
                     socket.inet_aton(i4['addr'])
        try:
            net4.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
                            ssdp4mcast)
        except socket.error as e:
            if e.errno != 98:
                # errno 98 can happen if aliased, skip for now
                raise
    net4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    net4.bind(('', 1900))
    net6.bind(('', 1900))
    peerbymacaddress = {}
    while True:
        try:
            newmacs = set([])
            machandlers = {}
            r, _, _ = select.select((net4, net6), (), (), 60)
            while r:
                for s in r:
                    (rsp, peer) = s.recvfrom(9000)
                    if rsp[:4] == b'PING':
                        continue
                    rsp = rsp.split(b'\r\n')
                    method, _, _ = rsp[0].split(b' ', 2)
                    if method == b'NOTIFY':
                        ip = peer[0].partition('%')[0]
                        if peer in known_peers:
                            continue
                        if ip not in neighutil.neightable:
                            neighutil.update_neigh()
                        if ip not in neighutil.neightable:
                            continue
                        mac = neighutil.neightable[ip]
                        known_peers.add(peer)
                        newmacs.add(mac)
                        if mac in peerbymacaddress:
                            peerbymacaddress[mac]['addresses'].append(peer)
                        else:
                            peerbymacaddress[mac] = {
                                'hwaddr': mac,
                                'addresses': [peer],
                            }
                            peerdata = peerbymacaddress[mac]
                            for headline in rsp[1:]:
                                if not headline:
                                    continue
                                headline = util.stringify(headline)
                                header, _, value = headline.partition(':')
                                header = header.strip()
                                value = value.strip()
                                if header == 'NT':
                                    peerdata['service'] = value
                                elif header == 'NTS':
                                    if value == 'ssdp:byebye':
                                        machandlers[mac] = byehandler
                                    elif value == 'ssdp:alive':
                                        machandlers[mac] = None  # handler
                    elif method == b'M-SEARCH':
                        if not uuidlookup:
                            continue
                        #ip = peer[0].partition('%')[0]
                        for headline in rsp[1:]:
                            if not headline:
                                continue
                            headline = util.stringify(headline)
                            headline = headline.partition(':')
                            if len(headline) < 3:
                                continue
                            if headline[0] == 'ST' and headline[-1].startswith(
                                    ' urn:xcat.org:service:confluent:'):
                                try:
                                    cfm.check_quorum()
                                except Exception:
                                    continue
                                for query in headline[-1].split('/'):
                                    if query.startswith('uuid='):
                                        curruuid = query.split('=',
                                                               1)[1].lower()
                                        node = uuidlookup(curruuid)
                                        if not node:
                                            break
                                        # Do not bother replying to a node that
                                        # we have no deployment activity
                                        # planned for
                                        cfg = cfm.ConfigManager(None)
                                        cfd = cfg.get_node_attributes(
                                            node, [
                                                'deployment.pendingprofile',
                                                'collective.managercandidates'
                                            ])
                                        if not cfd.get(node, {}).get(
                                                'deployment.pendingprofile',
                                            {}).get('value', None):
                                            break
                                        candmgrs = cfd.get(node, {}).get(
                                            'collective.managercandidates',
                                            {}).get('value', None)
                                        if candmgrs:
                                            candmgrs = noderange.NodeRange(
                                                candmgrs, cfg).nodes
                                            if collective.get_myname(
                                            ) not in candmgrs:
                                                break
                                        currtime = time.time()
                                        seconds = int(currtime)
                                        msecs = int(currtime * 1000 % 1000)
                                        reply = 'HTTP/1.1 200 OK\r\nNODENAME: {0}\r\nCURRTIME: {1}\r\nCURRMSECS: {2}\r\n'.format(
                                            node, seconds, msecs)
                                        if '%' in peer[0]:
                                            iface = peer[0].split('%', 1)[1]
                                            reply += 'MGTIFACE: {0}\r\n'.format(
                                                peer[0].split('%', 1)[1])
                                            ncfg = netutil.get_nic_config(
                                                cfg, node, ifidx=iface)
                                            if ncfg.get(
                                                    'matchesnodename', None):
                                                reply += 'DEFAULTNET: 1\r\n'
                                        elif not netutil.address_is_local(
                                                peer[0]):
                                            continue
                                        if not isinstance(reply, bytes):
                                            reply = reply.encode('utf8')
                                        s.sendto(reply, peer)
                r, _, _ = select.select((net4, net6), (), (), 0.2)
            for mac in newmacs:
                thehandler = machandlers.get(mac, None)
                if thehandler:
                    thehandler(peerbymacaddress[mac])
        except Exception:
            tracelog.log(traceback.format_exc(),
                         ltype=log.DataTypes.event,
                         event=log.Events.stacktrace)
Ejemplo n.º 5
0
def snoop(handler, byehandler=None):
    """Watch for SSDP notify messages

    The handler shall be called on any service coming online.
    byehandler is called whenever a system advertises that it is departing.
    If no byehandler is specified, byebye messages are ignored.  The handler is
    given (as possible), the mac address, a list of viable sockaddrs to reference
    the peer, and the notification type (e.g.
    'urn:dmtf-org:service:redfish-rest:1'

    :param handler:  A handler for online notifications from network
    :param byehandler: Optional handler for devices going off the network
    """
    # Normally, I like using v6/v4 agnostic socket. However, since we are
    # dabbling in multicast wizardry here, such sockets can cause big problems,
    # so we will have two distinct sockets
    known_peers = set([])
    net6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
    for ifidx in util.list_interface_indexes():
        v6grp = ssdp6mcast + struct.pack('=I', ifidx)
        net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, v6grp)
    net6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    net4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    for i4 in util.list_ips():
        ssdp4mcast = socket.inet_pton(socket.AF_INET, mcastv4addr) + \
                     socket.inet_aton(i4['addr'])
        net4.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
                        ssdp4mcast)
    net4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    net4.bind(('', 1900))
    net6.bind(('', 1900))
    peerbymacaddress = {}
    while True:
        newmacs = set([])
        machandlers = {}
        r, _, _ = select.select((net4, net6), (), (), 60)
        neighutil.update_neigh()
        while r:
            for s in r:
                (rsp, peer) = s.recvfrom(9000)
                rsp = rsp.split('\r\n')
                method, _, _ = rsp[0].split(' ', 2)
                if method == 'NOTIFY':
                    ip = peer[0].partition('%')[0]
                    if ip not in neighutil.neightable:
                        continue
                    if peer in known_peers:
                        continue
                    mac = neighutil.neightable[ip]
                    known_peers.add(peer)
                    newmacs.add(mac)
                    if mac in peerbymacaddress:
                        peerbymacaddress[mac]['peers'].append(peer)
                    else:
                        peerbymacaddress[mac] = {
                            'hwaddr': mac,
                            'peers': [peer],
                        }
                        peerdata = peerbymacaddress[mac]
                        for headline in rsp[1:]:
                            if not headline:
                                continue
                            header, _, value = headline.partition(':')
                            header = header.strip()
                            value = value.strip()
                            if header == 'NT':
                                peerdata['service'] = value
                            elif header == 'NTS':
                                if value == 'ssdp:byebye':
                                    machandlers[mac] = byehandler
                                elif value == 'ssdp:alive':
                                    machandlers[mac] = handler
            r, _, _ = select.select((net4, net6), (), (), 0.1)
        for mac in newmacs:
            thehandler = machandlers.get(mac, None)
            if thehandler:
                thehandler(peerbymacaddress[mac])
Ejemplo n.º 6
0
def snoop(handler):
    """Watch for SLP activity

    handler will be called with a dictionary of relevant attributes

    :param handler:
    :return:
    """
    active_scan(handler)
    net = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    net.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
    slpg = socket.inet_pton(socket.AF_INET6, 'ff01::123')
    slpg2 = socket.inet_pton(socket.AF_INET6, 'ff02::123')
    for i6idx in util.list_interface_indexes():
        mreq = slpg + struct.pack('=I', i6idx)
        net.setsockopt(IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
        mreq = slpg2 + struct.pack('=I', i6idx)
        net.setsockopt(IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
    net4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    net.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    net4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    for i4 in util.list_ips():
        if 'broadcast' not in i4:
            continue
        slpmcast = socket.inet_aton('239.255.255.253') + \
            socket.inet_aton(i4['addr'])
        try:
            net4.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
                            slpmcast)
        except socket.error as e:
            if e.errno != 98:
                raise
            # socket in use can occur when aliased ipv4 are encountered
    net.bind(('', 427))
    net4.bind(('', 427))

    while True:
        newmacs = set([])
        r, _, _ = select.select((net, net4), (), (), 60)
        # clear known_peers and peerbymacaddress
        # to avoid stale info getting in...
        # rely upon the select(0.2) to catch rapid fire and aggregate ip
        # addresses that come close together
        # calling code needs to understand deeper context, as snoop
        # will now yield dupe info over time
        known_peers = set([])
        peerbymacaddress = {}
        neighutil.update_neigh()
        while r:
            for s in r:
                (rsp, peer) = s.recvfrom(9000)
                ip = peer[0].partition('%')[0]
                if ip not in neighutil.neightable:
                    continue
                if peer in known_peers:
                    continue
                known_peers.add(peer)
                mac = neighutil.neightable[ip]
                if mac in peerbymacaddress:
                    peerbymacaddress[mac]['addresses'].append(peer)
                else:
                    q = query_srvtypes(peer)
                    if not q or not q[0]:
                        # SLP might have started and not ready yet
                        # ignore for now
                        known_peers.discard(peer)
                        continue
                    # we want to prioritize the very well known services
                    svcs = []
                    for svc in q:
                        if svc in _slp_services:
                            svcs.insert(0, svc)
                        else:
                            svcs.append(svc)
                    peerbymacaddress[mac] = {
                        'services': svcs,
                        'addresses': [peer],
                    }
                newmacs.add(mac)
            r, _, _ = select.select((net, net4), (), (), 0.2)
        for mac in newmacs:
            peerbymacaddress[mac]['xid'] = 1
            _add_attributes(peerbymacaddress[mac])
            peerbymacaddress[mac]['hwaddr'] = mac
            handler(peerbymacaddress[mac])