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:
@@ -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():
|
||||
|
||||
@@ -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'])
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user