From acf67a6c819e9665c9b9970462229ae70cbc5089 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 12 Jul 2019 17:04:14 -0400 Subject: [PATCH 1/2] Implement node search for confluent This is a viable client to find and get ones node identity. Node credentials are a separate concern, to be handled later. --- confluent_server/confluent/discovery/core.py | 7 +- .../confluent/discovery/protocols/ssdp.py | 110 +++++++++++------- misc/copernicus.c | 34 +++++- 3 files changed, 102 insertions(+), 49 deletions(-) diff --git a/confluent_server/confluent/discovery/core.py b/confluent_server/confluent/discovery/core.py index 10db839b..5b90dcd4 100644 --- a/confluent_server/confluent/discovery/core.py +++ b/confluent_server/confluent/discovery/core.py @@ -65,7 +65,7 @@ import base64 import confluent.config.configmanager as cfm import confluent.collective.manager as collective import confluent.discovery.protocols.pxe as pxe -#import confluent.discovery.protocols.ssdp as ssdp +import confluent.discovery.protocols.ssdp as ssdp import confluent.discovery.protocols.slp as slp import confluent.discovery.handlers.imm as imm import confluent.discovery.handlers.pxe as pxeh @@ -857,6 +857,8 @@ def get_nodename_from_chained_smms(cfg, handler, info): nodename = newnodename return nodename +def get_node_by_uuid(uuid): + return nodes_by_uuid.get(uuid, None) def get_nodename_from_enclosures(cfg, info): nodename = None @@ -1213,8 +1215,7 @@ def start_detection(): if rechecker is None: rechecktime = util.monotonic_time() + 900 rechecker = eventlet.spawn_after(900, _periodic_recheck, cfg) - - # eventlet.spawn_n(ssdp.snoop, safe_detected) + eventlet.spawn_n(ssdp.snoop, None, None, ssdp, get_node_by_uuid) def stop_autosense(): for watcher in list(autosensors): diff --git a/confluent_server/confluent/discovery/protocols/ssdp.py b/confluent_server/confluent/discovery/protocols/ssdp.py index 3ad43111..fdb355bd 100644 --- a/confluent_server/confluent/discovery/protocols/ssdp.py +++ b/confluent_server/confluent/discovery/protocols/ssdp.py @@ -30,9 +30,11 @@ import confluent.neighutil as neighutil import confluent.util as util +import confluent.log as log import eventlet.green.select as select import eventlet.green.socket as socket import struct +import traceback mcastv4addr = '239.255.255.250' mcastv6addr = 'ff02::c' @@ -51,7 +53,7 @@ def scan(services, target=None): yield rply -def snoop(handler, byehandler=None): +def snoop(handler, byehandler=None, protocol=None, uuidlookup=None): """Watch for SSDP notify messages The handler shall be called on any service coming online. @@ -67,6 +69,7 @@ def snoop(handler, byehandler=None): # 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) @@ -85,50 +88,73 @@ def snoop(handler, byehandler=None): 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] + try: + 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] = None # handler + elif method == 'M-SEARCH': + if not uuidlookup: + continue + #ip = peer[0].partition('%')[0] 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]) + headline = headline.partition(':') + if len(headline) < 3: + continue + if headline[0] == 'ST' and headline[-1].startswith(' urn:xcat.org:service:confluent:'): + for query in headline[-1].split('/'): + if query.startswith('uuid='): + curruuid = query.split('=', 1)[1].lower() + node = uuidlookup(curruuid) + if not node: + break + reply = 'HTTP/1.1 200 OK\r\nNODENAME: {0}'.format(node) + 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) def _find_service(service, target): diff --git a/misc/copernicus.c b/misc/copernicus.c index a9943f11..0a1a1bc0 100644 --- a/misc/copernicus.c +++ b/misc/copernicus.c @@ -68,6 +68,8 @@ int main(int argc, char* argv[]) { struct sockaddr_in6 addr, dst; struct sockaddr_in addr4, dst4; char msg[1024]; + char *nodenameidx; + char nodename[1024]; char lastmsg[1024]; int ifidx, offset; fd_set rfds; @@ -141,19 +143,43 @@ int main(int argc, char* argv[]) { if (ifidx == -1) perror("Unable to select"); if (ifidx) { if (FD_ISSET(n4, &rfds)) { - recvfrom(n4, msg, 1024, 0, (struct sockaddr *)&dst4, &dst4size); + memset(msg, 0, 1024); + /* Deny packet access to the last 24 bytes to assure null */ + recvfrom(n4, msg, 1000, 0, (struct sockaddr *)&dst4, &dst4size); + if (nodenameidx = strstr(msg, "NODENAME: ")) { + nodenameidx += 10; + strncpy(nodename, nodenameidx, 1024); + nodenameidx = strstr(nodenameidx, "\r"); + if (nodenameidx) { nodenameidx[0] = 0; } + printf("NODENAME: %s\n", nodename); + } + memset(msg, 0, 1024); inet_ntop(dst4.sin_family, &dst4.sin_addr, msg, dst4size); /* Take measure from printing out the same ip twice in a row */ if (strncmp(lastmsg, msg, 1024) != 0) { - printf("%s\n", msg); + printf("MANAGER: %s\n", msg); strncpy(lastmsg, msg, 1024); } } if (FD_ISSET(ns, &rfds)) { - recvfrom(ns, msg, 1024, 0, (struct sockaddr *)&dst, &dstsize); + memset(msg, 0, 1024); + /* Deny packet access to the last 24 bytes to assure null */ + recvfrom(ns, msg, 1000, 0, (struct sockaddr *)&dst, &dstsize); + if (nodenameidx = strstr(msg, "NODENAME: ")) { + nodenameidx += 10; + strncpy(nodename, nodenameidx, 1024); + nodenameidx = strstr(nodenameidx, "\r"); + if (nodenameidx) { nodenameidx[0] = 0; } + printf("NODENAME: %s\n", nodename); + } + memset(msg, 0, 1024); inet_ntop(dst.sin6_family, &dst.sin6_addr, msg, dstsize); if (strncmp(lastmsg, msg, 1024) != 0) { - printf("%s\n", msg); + printf("MANAGER: %s", msg); + if (strncmp(msg, "fe80::", 6) == 0) { + printf("%%%u", dst.sin6_scope_id); + } + printf("\n"); strncpy(lastmsg, msg, 1024); } } From 54f36e259fefc252efa51da6df200105999ad722 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 15 Jul 2019 10:30:36 -0400 Subject: [PATCH 2/2] Avoid copernicus printout of more duplicate data Separate v4 and v6 results for better chance of success in dropping duplicate packets. --- misc/copernicus.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/misc/copernicus.c b/misc/copernicus.c index 0a1a1bc0..f60ff3b8 100644 --- a/misc/copernicus.c +++ b/misc/copernicus.c @@ -70,7 +70,9 @@ int main(int argc, char* argv[]) { char msg[1024]; char *nodenameidx; char nodename[1024]; + char lastnodename[1024]; char lastmsg[1024]; + char last6msg[1024]; int ifidx, offset; fd_set rfds; struct timeval tv; @@ -82,6 +84,10 @@ int main(int argc, char* argv[]) { memset(&addr, 0, sizeof(addr)); memset(&dst, 0, sizeof(dst)); memset(&dst4, 0, sizeof(dst4)); + memset(nodename, 0, 1024); + memset(lastnodename, 0, 1024); + memset(lastmsg, 0, 1024); + memset(last6msg, 0, 1024); addr.sin6_family = AF_INET6; addr.sin6_addr = in6addr_any; addr.sin6_port = htons(190); @@ -151,7 +157,10 @@ int main(int argc, char* argv[]) { strncpy(nodename, nodenameidx, 1024); nodenameidx = strstr(nodenameidx, "\r"); if (nodenameidx) { nodenameidx[0] = 0; } - printf("NODENAME: %s\n", nodename); + if (strncmp(lastnodename, nodename, 1024) != 0) { + printf("NODENAME: %s\n", nodename); + strncpy(lastnodename, nodename, 1024); + } } memset(msg, 0, 1024); inet_ntop(dst4.sin_family, &dst4.sin_addr, msg, dst4size); @@ -170,17 +179,20 @@ int main(int argc, char* argv[]) { strncpy(nodename, nodenameidx, 1024); nodenameidx = strstr(nodenameidx, "\r"); if (nodenameidx) { nodenameidx[0] = 0; } - printf("NODENAME: %s\n", nodename); + if (strncmp(lastnodename, nodename, 1024) != 0) { + printf("NODENAME: %s\n", nodename); + strncpy(lastnodename, nodename, 1024); + } } memset(msg, 0, 1024); inet_ntop(dst.sin6_family, &dst.sin6_addr, msg, dstsize); - if (strncmp(lastmsg, msg, 1024) != 0) { + if (strncmp(last6msg, msg, 1024) != 0) { printf("MANAGER: %s", msg); if (strncmp(msg, "fe80::", 6) == 0) { printf("%%%u", dst.sin6_scope_id); } printf("\n"); - strncpy(lastmsg, msg, 1024); + strncpy(last6msg, msg, 1024); } } }