From 596fcb0f4c1e908250248e482bdc9b0a7995dfb0 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 6 Sep 2022 16:08:31 -0400 Subject: [PATCH] Implement mitigations for ovewhelming SSDP First, for a given contiguous set of snoop activity, start ignoring a given peer during that contiguous chenk after it has been considered once. Further, make get_hwaddr cheaper for attempts against remote IPs. To facilitate the above, create an efficient 'ip_is_local' to be a relatively cheap function, with potential to cache result in future if it needs to be even cheaper. --- .../confluent/discovery/protocols/ssdp.py | 5 +++++ confluent_server/confluent/neighutil.py | 3 ++- confluent_server/confluent/netutil.py | 13 +++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/confluent_server/confluent/discovery/protocols/ssdp.py b/confluent_server/confluent/discovery/protocols/ssdp.py index e8a8b36e..3a3eb49a 100644 --- a/confluent_server/confluent/discovery/protocols/ssdp.py +++ b/confluent_server/confluent/discovery/protocols/ssdp.py @@ -142,6 +142,7 @@ def snoop(handler, byehandler=None, protocol=None, uuidlookup=None): tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event, event=log.Events.stacktrace) known_peers = set([]) + recent_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(): @@ -171,11 +172,14 @@ def snoop(handler, byehandler=None, protocol=None, uuidlookup=None): r = select.select((net4, net6), (), (), 60) if r: r = r[0] + recent_peers = set([]) while r: for s in r: (rsp, peer) = s.recvfrom(9000) if rsp[:4] == b'PING': continue + if peer in recent_peers: + continue rsp = rsp.split(b'\r\n') if b' ' not in rsp[0]: continue @@ -183,6 +187,7 @@ def snoop(handler, byehandler=None, protocol=None, uuidlookup=None): if method == b'NOTIFY': if peer in known_peers: continue + recent_peers.add(peer) mac = neighutil.get_hwaddr(peer[0]) if not mac: probepeer = (peer[0], struct.unpack('H', os.urandom(2))[0] | 1025) + peer[2:] diff --git a/confluent_server/confluent/neighutil.py b/confluent_server/confluent/neighutil.py index 11068378..5841f868 100644 --- a/confluent_server/confluent/neighutil.py +++ b/confluent_server/confluent/neighutil.py @@ -16,6 +16,7 @@ # A consolidated manage of neighbor table information management. +import confluent.netutil as netutil import confluent.util as util import os import eventlet.semaphore as semaphore @@ -96,7 +97,7 @@ def get_hwaddr(ipaddr): _update_neigh() updated = True hwaddr = neightable.get(ipaddr, None) - if not hwaddr and not updated: + if not hwaddr and not updated and netutil.ip_is_local(ipaddr): _update_neigh() hwaddr = neightable.get(ipaddr, None) if hwaddr: diff --git a/confluent_server/confluent/netutil.py b/confluent_server/confluent/netutil.py index feb0f02f..9bf26bdc 100644 --- a/confluent_server/confluent/netutil.py +++ b/confluent_server/confluent/netutil.py @@ -84,6 +84,19 @@ def ip_on_same_subnet(first, second, prefix): return ip & mask == oip & mask +def ip_is_local(ipaddr): + fam, _, _, _, ainfo = socket.getaddrinfo(ipaddr, 0, proto=socket.IPPROTO_UDP)[0] + ipn = socket.inet_pton(fam, ainfo[0]) + if fam == socket.AF_INET6 and ipn.startswith(b'\xfe\x80'): + return True + for addr in get_my_addresses(): + if fam != addr[0]: + continue + if ipn_on_same_subnet(addr[0], ipn, addr[1], addr[2]): + return True + return False + + def address_is_local(address): for iface in netifaces.interfaces(): for i4 in netifaces.ifaddresses(iface).get(2, []):