Skip to content

Commit

Permalink
Add tls support (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
mib1185 authored Sep 14, 2024
1 parent 5cc652a commit 446498c
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![Supports aarch64 Architecture][aarch64-shield] ![Supports amd64 Architecture][amd64-shield] ![Supports armhf Architecture][armhf-shield] ![Supports armv7 Architecture][armv7-shield] ![Supports i386 Architecture][i386-shield]

... to send your HAOS logs to a remote syslog server
... to send your HAOS logs to a remote syslog server. UDP and TCP transport is support, as also TLS encrypted transport.

## How to use this repository

Expand Down
4 changes: 4 additions & 0 deletions syslog/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 0.3.0

- Add tls support

## 0.2.0

- Determine correct syslog level for ha core, supervisor and haos host messages
Expand Down
6 changes: 5 additions & 1 deletion syslog/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@ Add-on configuration:
syslog_host: syslog.local
syslog_port: 514
syslog_protocol: udp
syslog_ssl: false
syslog_ssl_verfify: false
```
| key | name | description |
| --- | ---- | ----------- |
| `syslog_host` | Syslog host | The hostname or IP address of the remote syslog server to send HAOS logs to. |
| `syslog_port` | Syslog port | The port of the remote syslog server to send HAOS logs to. |
| `syslog_protocol` | Transfer protocol | The protocol to be used to send HAOS logs. |
| `syslog_ssl` | SSL encryption | Whether or not to to use ssl encryption (only supported with tcp). |
| `syslog_ssl_verfify` | SSL verify | Whether or not to verify ssl certificate. |

## Support

In case you've found a bug, please [open an issue on our GitHub][issue].
In case you've found a bug, please [open an issue on GitHub][issue].

[issue]: https://github.com/mib1185/ha-addon-syslog/issues
6 changes: 5 additions & 1 deletion syslog/config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "Syslog"
version: "0.2.0"
version: "0.3.0"
slug: "syslog"
description: "Send your HAOS logs to a remote syslog server"
url: "https://github.com/mib1185/ha-addon-syslog"
Expand All @@ -17,7 +17,11 @@ options:
syslog_host: syslog.local
syslog_port: 514
syslog_protocol: udp
syslog_ssl: false
syslog_ssl_verify: true
schema:
syslog_host: str
syslog_port: int
syslog_protocol: list(udp|tcp)
syslog_ssl: bool
syslog_ssl_verify: bool
88 changes: 85 additions & 3 deletions syslog/journal2syslog.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import logging
import logging.handlers
from os import environ
import re
import socket
import ssl
from os import environ

from systemd import journal

SYSLOG_HOST = str(environ["SYSLOG_HOST"])
SYSLOG_PORT = int(environ["SYSLOG_PORT"])
SYSLOG_PROTO = str(environ["SYSLOG_PROTO"])
SYSLOG_SSL = True if environ["SYSLOG_SSL"] == "true" else False
SYSLOG_SSL_VERIFY = True if environ["SYSLOG_SSL_VERIFY"] == "true" else False
HAOS_HOSTNAME = str(environ["HAOS_HOSTNAME"])

LOGGING_NAME_TO_LEVEL_MAPPING = logging.getLevelNamesMapping()
Expand All @@ -33,6 +37,78 @@
}


class TlsSysLogHandler(logging.handlers.SysLogHandler):
def __init__(
self,
address: tuple[str, int]
| str = ("localhost", logging.handlers.SYSLOG_UDP_PORT),
facility: str | int = logging.handlers.SysLogHandler.LOG_USER,
socktype: logging.handlers.SocketKind | None = None,
ssl: bool | ssl.SSLContext = False,
) -> None:
self.ssl = ssl
if ssl and socktype != socket.SOCK_STREAM:
raise RuntimeError("TLS is only support for TCP connections")
super().__init__(address, facility, socktype)

def _wrap_sock_ssl(self, sock: socket.socket, host: str):
"""Wrap a tcp socket into a ssl context."""
if isinstance(self.ssl, ssl.SSLContext):
context = self.ssl
else:
context = ssl.create_default_context()

return context.wrap_socket(sock, server_hostname=host)

def createSocket(self):
"""
Try to create a socket and, if it's not a datagram socket, connect it
to the other end. This method is called during handler initialization,
but it's not regarded as an error if the other end isn't listening yet
--- the method will be called again when emitting an event,
if there is no socket at that point.
"""
address = self.address
socktype = self.socktype

if isinstance(address, str):
self.unixsocket = True
# Syslog server may be unavailable during handler initialisation.
# C's openlog() function also ignores connection errors.
# Moreover, we ignore these errors while logging, so it's not worse
# to ignore it also here.
try:
self._connect_unixsocket(address)
except OSError:
pass
else:
self.unixsocket = False
if socktype is None:
socktype = socket.SOCK_DGRAM
host, port = address
ress = socket.getaddrinfo(host, port, 0, socktype)
if not ress:
raise OSError("getaddrinfo returns an empty list")
for res in ress:
af, socktype, proto, _, sa = res
err = sock = None
try:
sock = socket.socket(af, socktype, proto)
if self.ssl:
sock = self._wrap_sock_ssl(sock, host)
if socktype == socket.SOCK_STREAM:
sock.connect(sa)
break
except (OSError, ssl.SSLError) as exc:
err = exc
if sock is not None:
sock.close()
if err is not None:
raise err
self.socket = sock
self.socktype = socktype


def parse_log_level(message: str, container_name: str) -> int:
"""
Try to determine logging level from message
Expand Down Expand Up @@ -64,8 +140,14 @@ def parse_log_level(message: str, container_name: str) -> int:
else:
socktype = socket.SOCK_STREAM

syslog_handler = logging.handlers.SysLogHandler(
address=(SYSLOG_HOST, SYSLOG_PORT), socktype=socktype
use_ssl = SYSLOG_SSL
if SYSLOG_SSL and not SYSLOG_SSL_VERIFY:
use_ssl = ssl.create_default_context()
use_ssl.check_hostname = False
use_ssl.verify_mode = ssl.CERT_NONE

syslog_handler = TlsSysLogHandler(
address=(SYSLOG_HOST, SYSLOG_PORT), socktype=socktype, ssl=use_ssl
)
formatter = logging.Formatter(
f"%(asctime)s %(ip)s %(prog)s: %(message)s",
Expand Down
4 changes: 4 additions & 0 deletions syslog/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ SYSLOG_PORT=$(bashio::config 'syslog_port')
export SYSLOG_PORT
SYSLOG_PROTO=$(bashio::config 'syslog_protocol')
export SYSLOG_PROTO
SYSLOG_SSL=$(bashio::config 'syslog_ssl')
export SYSLOG_SSL
SYSLOG_SSL_VERIFY=$(bashio::config 'syslog_ssl_verify')
export SYSLOG_SSL_VERIFY
HAOS_HOSTNAME=$(bashio::info.hostname)
export HAOS_HOSTNAME

Expand Down
6 changes: 6 additions & 0 deletions syslog/translations/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ configuration:
syslog_protocol:
name: Übertragungsprotokol
description: Das Übertragungsprotokol welches zum Senden der HAOS-Logs verwendet werden soll.
syslog_ssl:
name: SSL Verschlüsselung
description: Aktivieren oder deaktivieren der SSL Verschlüsselung (wird nur bei tcp unterstützt).
syslog_ssl_verify:
name: SSL-Zertifikat überprüfen
description: Prüfung des SSL-Zertifikate aktivieren oder dekativieren.
6 changes: 6 additions & 0 deletions syslog/translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ configuration:
syslog_protocol:
name: Transfer protocol
description: The protocol to be used to send HAOS logs.
syslog_ssl:
name: SSL encryption
description: Whether or not to to use ssl encryption (only supported with tcp).
syslog_ssl_verify:
name: SSL verify
description: Whether or not to verify ssl certificate.

0 comments on commit 446498c

Please sign in to comment.