mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-06 00:00:47 -04:00
vici: Add vici python protocol handler
This commit is contained in:
parent
c7bb1dc3d9
commit
b26e142863
1
src/libcharon/plugins/vici/python/.gitignore
vendored
Normal file
1
src/libcharon/plugins/vici/python/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.pyc
|
0
src/libcharon/plugins/vici/python/vici/__init__.py
Normal file
0
src/libcharon/plugins/vici/python/vici/__init__.py
Normal file
4
src/libcharon/plugins/vici/python/vici/exception.py
Normal file
4
src/libcharon/plugins/vici/python/vici/exception.py
Normal file
@ -0,0 +1,4 @@
|
||||
"""Exception types that may be thrown by this library."""
|
||||
|
||||
class DeserializationException(Exception):
|
||||
"""Encountered an unexpected byte sequence or missing element type."""
|
194
src/libcharon/plugins/vici/python/vici/protocol.py
Normal file
194
src/libcharon/plugins/vici/python/vici/protocol.py
Normal file
@ -0,0 +1,194 @@
|
||||
import io
|
||||
import socket
|
||||
import struct
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from .exception import DeserializationException
|
||||
|
||||
|
||||
class Transport(object):
|
||||
HEADER_LENGTH = 4
|
||||
MAX_SEGMENT = 512 * 1024
|
||||
|
||||
def __init__(self, address="/var/run/charon.vici"):
|
||||
self.address = address
|
||||
self.socket = socket.socket(socket.AF_UNIX)
|
||||
self.socket.connect(address)
|
||||
|
||||
def send(self, packet):
|
||||
self.socket.sendall(struct.pack("!I", len(packet)) + packet)
|
||||
|
||||
def receive(self):
|
||||
raw_length = self.socket.recv(self.HEADER_LENGTH)
|
||||
length, = struct.unpack("!I", raw_length)
|
||||
payload = self.socket.recv(length)
|
||||
return payload
|
||||
|
||||
def close(self):
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
self.socket.close()
|
||||
|
||||
|
||||
class Packet(object):
|
||||
CMD_REQUEST = 0 # Named request message
|
||||
CMD_RESPONSE = 1 # Unnamed response message for a request
|
||||
CMD_UNKNOWN = 2 # Unnamed response if requested command is unknown
|
||||
EVENT_REGISTER = 3 # Named event registration request
|
||||
EVENT_UNREGISTER = 4 # Named event de-registration request
|
||||
EVENT_CONFIRM = 5 # Unnamed confirmation for event (de-)registration
|
||||
EVENT_UNKNOWN = 6 # Unnamed response if event (de-)registration failed
|
||||
EVENT = 7 # Named event message
|
||||
|
||||
ParsedPacket = namedtuple(
|
||||
"ParsedPacket",
|
||||
["response_type", "payload"]
|
||||
)
|
||||
|
||||
ParsedEventPacket = namedtuple(
|
||||
"ParsedEventPacket",
|
||||
["response_type", "event_type", "payload"]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _named_request(cls, request_type, request, message=None):
|
||||
payload = struct.pack("!BB", request_type, len(request)) + request
|
||||
if message is not None:
|
||||
return payload + message
|
||||
else:
|
||||
return payload
|
||||
|
||||
@classmethod
|
||||
def request(cls, command, message=None):
|
||||
return cls._named_request(cls.CMD_REQUEST, command, message)
|
||||
|
||||
@classmethod
|
||||
def register_event(cls, event_type):
|
||||
return cls._named_request(cls.EVENT_REGISTER, event_type)
|
||||
|
||||
@classmethod
|
||||
def unregister_event(cls, event_type):
|
||||
return cls._named_request(cls.EVENT_UNREGISTER, event_type)
|
||||
|
||||
@classmethod
|
||||
def parse(cls, packet):
|
||||
stream = FiniteStream(packet)
|
||||
response_type, = struct.unpack("!B", stream.read(1))
|
||||
|
||||
if response_type == cls.EVENT:
|
||||
length, = struct.unpack("!B", stream.read(1))
|
||||
event_type = stream.read(length)
|
||||
return cls.ParsedEventPacket(response_type, event_type, stream)
|
||||
else:
|
||||
return cls.ParsedPacket(response_type, stream)
|
||||
|
||||
|
||||
class Message(object):
|
||||
SECTION_START = 1 # Begin a new section having a name
|
||||
SECTION_END = 2 # End a previously started section
|
||||
KEY_VALUE = 3 # Define a value for a named key in the section
|
||||
LIST_START = 4 # Begin a named list for list items
|
||||
LIST_ITEM = 5 # Define an unnamed item value in the current list
|
||||
LIST_END = 6 # End a previously started list
|
||||
|
||||
@classmethod
|
||||
def serialize(cls, message):
|
||||
def encode_named_type(marker, name):
|
||||
name = str(name)
|
||||
return struct.pack("!BB", marker, len(name)) + name
|
||||
|
||||
def encode_blob(value):
|
||||
value = str(value)
|
||||
return struct.pack("!H", len(value)) + value
|
||||
|
||||
def serialize_list(lst):
|
||||
segment = str()
|
||||
for item in lst:
|
||||
segment += struct.pack("!B", cls.LIST_ITEM) + encode_blob(item)
|
||||
return segment
|
||||
|
||||
def serialize_dict(d):
|
||||
segment = str()
|
||||
for key, value in d.iteritems():
|
||||
if isinstance(value, dict):
|
||||
segment += (
|
||||
encode_named_type(cls.SECTION_START, key)
|
||||
+ serialize_dict(value)
|
||||
+ struct.pack("!B", cls.SECTION_END)
|
||||
)
|
||||
elif isinstance(value, list):
|
||||
segment += (
|
||||
encode_named_type(cls.LIST_START, key)
|
||||
+ serialize_list(value)
|
||||
+ struct.pack("!B", cls.LIST_END)
|
||||
)
|
||||
else:
|
||||
segment += (
|
||||
encode_named_type(cls.KEY_VALUE, key)
|
||||
+ encode_blob(value)
|
||||
)
|
||||
return segment
|
||||
|
||||
return serialize_dict(message)
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream):
|
||||
def decode_named_type(stream):
|
||||
length, = struct.unpack("!B", stream.read(1))
|
||||
return stream.read(length)
|
||||
|
||||
def decode_blob(stream):
|
||||
length, = struct.unpack("!H", stream.read(2))
|
||||
return stream.read(length)
|
||||
|
||||
def decode_list_item(stream):
|
||||
marker, = struct.unpack("!B", stream.read(1))
|
||||
while marker == cls.LIST_ITEM:
|
||||
yield decode_blob(stream)
|
||||
marker, = struct.unpack("!B", stream.read(1))
|
||||
|
||||
if marker != cls.LIST_END:
|
||||
raise DeserializationException(
|
||||
"Expected end of list at {pos}".format(pos=stream.tell())
|
||||
)
|
||||
|
||||
section = {}
|
||||
section_stack = []
|
||||
while stream.has_more():
|
||||
element_type, = struct.unpack("!B", stream.read(1))
|
||||
if element_type == cls.SECTION_START:
|
||||
section_name = decode_named_type(stream)
|
||||
new_section = {}
|
||||
section[section_name] = new_section
|
||||
section_stack.append(section)
|
||||
section = new_section
|
||||
|
||||
elif element_type == cls.LIST_START:
|
||||
list_name = decode_named_type(stream)
|
||||
section[list_name] = [item for item in decode_list_item(stream)]
|
||||
|
||||
elif element_type == cls.KEY_VALUE:
|
||||
key = decode_named_type(stream)
|
||||
section[key] = decode_blob(stream)
|
||||
|
||||
elif element_type == cls.SECTION_END:
|
||||
if len(section_stack):
|
||||
section = section_stack.pop()
|
||||
else:
|
||||
raise DeserializationException(
|
||||
"Unexpected end of section at {pos}".format(
|
||||
pos=stream.tell()
|
||||
)
|
||||
)
|
||||
|
||||
if len(section_stack):
|
||||
raise DeserializationException("Expected end of section")
|
||||
return section
|
||||
|
||||
|
||||
class FiniteStream(io.BytesIO):
|
||||
def __len__(self):
|
||||
return len(self.getvalue())
|
||||
|
||||
def has_more(self):
|
||||
return self.tell() < len(self)
|
Loading…
x
Reference in New Issue
Block a user