2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-09-29 00:31:09 +00:00

Initial SSDP work

Refactor relevant bits of SLP implementation and do SSDP.
Note it still needs the monitoring for SSDP NOTIFY packets.
Unfortunately, this is another protocol that embeds the
address into the packet, making it tricky to have a sane
reusable function for the v4/v6 multicast/broadcast scheme.
This commit is contained in:
Jarrod Johnson
2016-11-09 16:49:47 -05:00
parent 63431deffb
commit fff0488f89
4 changed files with 119 additions and 28 deletions
@@ -81,6 +81,10 @@
# * Management TLS fingerprint if validated (by switch publication or enclosure)
# * System TLS fingerprint if validated (by switch publication or system manager)
_slp_services = set([
'service:management-hardware.IBM:integrated-management-module2',
])
def add_validated_fingerprint(nodename, fingerprint, role='manager'):
"""Add a physically validated certificate fingerprint
@@ -162,4 +166,6 @@ class DiscoveredNode(object):
# validated by a secure validator.
pass
def detect_endpoint(mac, peers, services):
def start_detection():
+5 -28
View File
@@ -14,13 +14,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import netifaces
import os
import random
import select
import socket
import struct
import subprocess
import confluent.util as util
# SLP has a lot of ambition that was unfulfilled in practice.
@@ -67,15 +67,6 @@ def _refresh_neigh():
update_neigh()
def _list_ips():
# Used for getting addresses to indicate the multicast address
# as well as getting all the broadcast addresses
for iface in netifaces.interfaces():
addrs = netifaces.ifaddresses(iface)
if netifaces.AF_INET in addrs:
for addr in addrs[netifaces.AF_INET]:
yield addr
def _parse_slp_header(packet):
packet = bytearray(packet)
@@ -154,22 +145,6 @@ def _parse_slp_packet(packet, peer, rsps, xidmap):
_parse_SrvRply(parsed)
def list_interface_indexes():
# Getting the interface indexes in a portable manner
# would be better, but there's difficulty from a python perspective.
# For now be linux specific
try:
for iface in os.listdir('/sys/class/net/'):
ifile = open('/sys/class/net/{0}/ifindex'.format(iface), 'r')
intidx = int(ifile.read())
ifile.close()
yield intidx
except (IOError, WindowsError):
# Probably situation is non-Linux, just do limited support for
# such platforms until other people come alonge
return
def _v6mcasthash(srvtype):
# The hash algorithm described by RFC 3111
nums = bytearray(srvtype.encode('utf-8'))
@@ -249,7 +224,7 @@ def _find_srvtype(net, net4, srvtype, addresses, xid):
# local that do not work with link local
v6addrs.append(('ff01::1:' + v6hash, 427, 0, 0))
v6addrs.append(('ff02::1:' + v6hash, 427, 0, 0))
for idx in list_interface_indexes():
for idx in util.list_interface_indexes():
# IPv6 multicast is by index, so lead with that
net.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, idx)
for sa in v6addrs:
@@ -260,7 +235,7 @@ def _find_srvtype(net, net4, srvtype, addresses, xid):
# this can cause an error, skip such an interface
# case in point, 'lo'
pass
for i4 in _list_ips():
for i4 in util.list_ips():
if 'broadcast' not in i4:
continue
addr = i4['addr']
@@ -424,6 +399,8 @@ def snoop_slp(handler):
slpmcast = socket.inet_pton(socket.AF_INET, '239.255.255.253') + \
struct.pack('=I', socket.INADDR_ANY)
net4.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, slpmcast)
net.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
net4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
net.bind(('', 427))
net4.bind(('', 427))
peerbymacaddress = {}
@@ -0,0 +1,82 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Documented somewhat at
# http://buildingskb.schneider-electric.com/view.php?AID=15197
import confluent.util as util
import select
import socket
mcastv4addr = '239.255.255.250'
mcastv6addr = 'ff02::c'
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 find_targets(services, target=None):
for service in services:
_find_service(service, target)
def _find_service(service, target):
net4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
net6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
if target:
addrs = socket.getaddrinfo(target, 1900, 0, socket.SOCK_DGRAM)
for addr in addrs:
host = addr[4][0]
if addr[0] == socket.AF_INET:
net4.sendto(smsg.format(host, service), addr[4])
elif addr[0] == socket.AF_INET6:
host = '[{0}]'.format(host)
net6.sendto(smsg.format(host, service), addr[4])
else:
net4.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
for idx in util.list_interface_indexes():
net6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF,
idx)
try:
net6.sendto(smsg.format('[{0}]'.format(mcastv6addr), service
), (mcastv6addr, 1900, 0, 0))
except socket.error:
# ignore interfaces without ipv6 multicast causing error
pass
for i4 in util.list_ips():
if 'broadcast' not in i4:
continue
addr = i4['addr']
bcast = i4['broadcast']
net4.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF,
socket.inet_aton(addr))
net4.sendto(smsg.format(mcastv4addr, service),
(mcastv4addr, 1900))
net4.sendto(smsg.format(bcast, service), (bcast, 1900))
r, _, _ = select.select((net4, net6), (), (), 1)
while r:
for s in r:
(rsp, peer) = s.recvfrom(9000)
print(repr(rsp))
print(repr(peer))
r, _, _ = select.select((net4, net6), (), (), 1)
if __name__ == '__main__':
find_targets(['urn:dmtf-org:service:redfish-rest:1'])
+26
View File
@@ -20,10 +20,36 @@ import base64
import confluent.exceptions as cexc
import confluent.log as log
import hashlib
import netifaces
import os
import struct
def list_interface_indexes():
# Getting the interface indexes in a portable manner
# would be better, but there's difficulty from a python perspective.
# For now be linux specific
try:
for iface in os.listdir('/sys/class/net/'):
ifile = open('/sys/class/net/{0}/ifindex'.format(iface), 'r')
intidx = int(ifile.read())
ifile.close()
yield intidx
except (IOError, WindowsError):
# Probably situation is non-Linux, just do limited support for
# such platforms until other people come alonge
return
def list_ips():
# Used for getting addresses to indicate the multicast address
# as well as getting all the broadcast addresses
for iface in netifaces.interfaces():
addrs = netifaces.ifaddresses(iface)
if netifaces.AF_INET in addrs:
for addr in addrs[netifaces.AF_INET]:
yield addr
def randomstring(length=20):
"""Generate a random string of requested length