Beispiel #1
0
def addresses_match(addr1, addr2):
    """Check two network addresses for similarity

    Is it zero padded in one place, not zero padded in another?  Is one place by name and another by IP??
    Is one context getting a normal IPv4 address and another getting IPv4 in IPv6 notation?
    This function examines the two given names, performing the required changes to compare them for equivalency

    :param addr1:
    :param addr2:
    :return: True if the given addresses refer to the same thing
    """
    for addrinfo in socket.getaddrinfo(addr1, 0, 0, socket.SOCK_STREAM):
        rootaddr1 = socket.inet_pton(addrinfo[0], addrinfo[4][0])
        if addrinfo[
                0] == socket.AF_INET6 and rootaddr1[:
                                                    12] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff':
            # normalize to standard IPv4
            rootaddr1 = rootaddr1[-4:]
        for otherinfo in socket.getaddrinfo(addr2, 0, 0, socket.SOCK_STREAM):
            otheraddr = socket.inet_pton(otherinfo[0], otherinfo[4][0])
            if otherinfo[
                    0] == socket.AF_INET6 and otheraddr[:
                                                        12] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff':
                otheraddr = otheraddr[-4:]
            if otheraddr == rootaddr1:
                return True
    return False
Beispiel #2
0
def mask_to_cidr(mask):
    maskn = socket.inet_pton(socket.AF_INET, mask)
    maskn = struct.unpack('!I', maskn)[0]
    cidr = 32
    while maskn & 0b1 == 0 and cidr > 0:
        cidr -= 1
        maskn >>= 1
    return cidr
Beispiel #3
0
def rsync_ip(ip):
    """
    Transform ip string to an rsync-compatible form

    Will return ipv4 addresses unchanged, but will nest ipv6 addresses
    inside square brackets.

    :param ip: an ip string (ipv4 or ipv6)

    :returns: a string ip address
    """
    try:
        socket.inet_pton(socket.AF_INET6, ip)
    except socket.error:  # it's IPv4
        return ip
    else:
        return '[%s]' % ip
Beispiel #4
0
def rsync_ip(ip):
    """
    Transform ip string to an rsync-compatible form

    Will return ipv4 addresses unchanged, but will nest ipv6 addresses
    inside square brackets.

    :param ip: an ip string (ipv4 or ipv6)

    :returns: a string ip address
    """
    try:
        socket.inet_pton(socket.AF_INET6, ip)
    except socket.error:  # it's IPv4
        return ip
    else:
        return '[%s]' % ip
Beispiel #5
0
def ip_on_same_subnet(first, second, prefix):
    addrinf = socket.getaddrinfo(first, None, 0, socket.SOCK_STREAM)[0]
    fam = addrinf[0]
    ip = socket.inet_pton(fam, addrinf[-1][0])
    ip = int(codecs.encode(bytes(ip), 'hex'), 16)
    addrinf = socket.getaddrinfo(second, None, 0, socket.SOCK_STREAM)[0]
    if fam != addrinf[0]:
        return False
    oip = socket.inet_pton(fam, addrinf[-1][0])
    oip = int(codecs.encode(bytes(oip), 'hex'), 16)
    if fam == socket.AF_INET:
        addrlen = 32
    elif fam == socket.AF_INET6:
        addrlen = 128
    else:
        raise Exception("Unknown address family {0}".format(fam))
    mask = 2**prefix - 1 << (addrlen - prefix)
    return ip & mask == oip & mask
Beispiel #6
0
def ip_on_same_subnet(first, second, prefix):
    if first.startswith('::ffff:') and '.' in first:
        first = first.replace('::ffff:', '')
    if second.startswith('::ffff:') and '.' in second:
        second = second.replace('::ffff:', '')
    addrinf = socket.getaddrinfo(first, None, 0, socket.SOCK_STREAM)[0]
    fam = addrinf[0]
    ip = socket.inet_pton(fam, addrinf[-1][0])
    ip = int(codecs.encode(bytes(ip), 'hex'), 16)
    addrinf = socket.getaddrinfo(second, None, 0, socket.SOCK_STREAM)[0]
    if fam != addrinf[0]:
        return False
    txtaddr = addrinf[-1][0].split('%')[0]
    oip = socket.inet_pton(fam, txtaddr)
    oip = int(codecs.encode(bytes(oip), 'hex'), 16)
    if fam == socket.AF_INET:
        addrlen = 32
    elif fam == socket.AF_INET6:
        addrlen = 128
    else:
        raise Exception("Unknown address family {0}".format(fam))
    mask = 2**prefix - 1 << (addrlen - prefix)
    return ip & mask == oip & mask
Beispiel #7
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)
Beispiel #8
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)
Beispiel #9
0
import confluent.netutil as netutil
import eventlet.green.select as select
import eventlet.green.socket as socket
import eventlet.greenpool as gp
import time
try:
    from eventlet.green.urllib.request import urlopen
except (ImportError, AssertionError):
    from eventlet.green.urllib2 import urlopen
import struct
import traceback

mcastv4addr = '239.255.255.250'
mcastv6addr = 'ff02::c'

ssdp6mcast = socket.inet_pton(socket.AF_INET6, mcastv6addr)
smsg = ('M-SEARCH * HTTP/1.1\r\n'
        'HOST: {0}:1900\r\n'
        'MAN: "ssdp:discover"\r\n'
        'ST: {1}\r\n'
        'MX: 3\r\n\r\n')


def active_scan(handler, protocol=None):
    known_peers = set([])
    for scanned in scan(['urn:dmtf-org:service:redfish-rest:1']):
        for addr in scanned['addresses']:
            ip = addr[0].partition('%')[0]  # discard scope if present
            if ip not in neighutil.neightable:
                continue
            if addr in known_peers:
Beispiel #10
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])
Beispiel #11
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])