Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[syslog] Add basic support for encrypted syslog via TLS
Encrypted syslog seems not yet to be standardised, but is supported by some existing syslog servers. Signed-off-by: Michael Brown <mcb30@ipxe.org>
- Loading branch information
Showing
4 changed files
with
282 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,275 @@ | ||
/* | ||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License as | ||
* published by the Free Software Foundation; either version 2 of the | ||
* License, or any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
*/ | ||
|
||
FILE_LICENCE ( GPL2_OR_LATER ); | ||
|
||
/** @file | ||
* | ||
* Encrypted syslog protocol | ||
* | ||
*/ | ||
|
||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include <byteswap.h> | ||
#include <ipxe/xfer.h> | ||
#include <ipxe/open.h> | ||
#include <ipxe/tcpip.h> | ||
#include <ipxe/dhcp.h> | ||
#include <ipxe/settings.h> | ||
#include <ipxe/console.h> | ||
#include <ipxe/lineconsole.h> | ||
#include <ipxe/tls.h> | ||
#include <ipxe/syslog.h> | ||
#include <config/console.h> | ||
|
||
/* Set default console usage if applicable */ | ||
#if ! ( defined ( CONSOLE_SYSLOGS ) && CONSOLE_EXPLICIT ( CONSOLE_SYSLOGS ) ) | ||
#undef CONSOLE_SYSLOGS | ||
#define CONSOLE_SYSLOGS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI ) | ||
#endif | ||
|
||
struct console_driver syslogs_console __console_driver; | ||
|
||
/** The encrypted syslog server */ | ||
static struct sockaddr_tcpip logserver = { | ||
.st_family = AF_INET, | ||
.st_port = htons ( SYSLOG_PORT ), | ||
}; | ||
|
||
/** | ||
* Handle encrypted syslog TLS interface close | ||
* | ||
* @v intf Interface | ||
* @v rc Reason for close | ||
*/ | ||
static void syslogs_close ( struct interface *intf __unused, int rc ) { | ||
|
||
DBG ( "SYSLOGS console disconnected: %s\n", strerror ( rc ) ); | ||
} | ||
|
||
/** | ||
* Handle encrypted syslog TLS interface window change | ||
* | ||
* @v intf Interface | ||
*/ | ||
static void syslogs_window_changed ( struct interface *intf ) { | ||
|
||
/* Mark console as enabled when window first opens, indicating | ||
* that TLS negotiation is complete. (Do not disable console | ||
* when window closes again, since TCP will close the window | ||
* whenever there is unACKed data.) | ||
*/ | ||
if ( xfer_window ( intf ) ) { | ||
if ( syslogs_console.disabled ) | ||
DBG ( "SYSLOGS console connected\n" ); | ||
syslogs_console.disabled = 0; | ||
} | ||
} | ||
|
||
/** Encrypted syslog TLS interface operations */ | ||
static struct interface_operation syslogs_operations[] = { | ||
INTF_OP ( xfer_window_changed, struct interface *, | ||
syslogs_window_changed ), | ||
INTF_OP ( intf_close, struct interface *, syslogs_close ), | ||
}; | ||
|
||
/** Encrypted syslog TLS interface descriptor */ | ||
static struct interface_descriptor syslogs_desc = | ||
INTF_DESC_PURE ( syslogs_operations ); | ||
|
||
/** The encrypted syslog TLS interface */ | ||
static struct interface syslogs = INTF_INIT ( syslogs_desc ); | ||
|
||
/****************************************************************************** | ||
* | ||
* Console driver | ||
* | ||
****************************************************************************** | ||
*/ | ||
|
||
/** Encrypted syslog line buffer */ | ||
static char syslogs_buffer[SYSLOG_BUFSIZE]; | ||
|
||
/** Encrypted syslog severity */ | ||
static unsigned int syslogs_severity = SYSLOG_DEFAULT_SEVERITY; | ||
|
||
/** | ||
* Handle ANSI set encrypted syslog priority (private sequence) | ||
* | ||
* @v count Parameter count | ||
* @v params List of graphic rendition aspects | ||
*/ | ||
static void syslogs_handle_priority ( unsigned int count __unused, | ||
int params[] ) { | ||
if ( params[0] >= 0 ) { | ||
syslogs_severity = params[0]; | ||
} else { | ||
syslogs_severity = SYSLOG_DEFAULT_SEVERITY; | ||
} | ||
} | ||
|
||
/** Encrypted syslog ANSI escape sequence handlers */ | ||
static struct ansiesc_handler syslogs_handlers[] = { | ||
{ ANSIESC_LOG_PRIORITY, syslogs_handle_priority }, | ||
{ 0, NULL } | ||
}; | ||
|
||
/** Encrypted syslog line console */ | ||
static struct line_console syslogs_line = { | ||
.buffer = syslogs_buffer, | ||
.len = sizeof ( syslogs_buffer ), | ||
.ctx = { | ||
.handlers = syslogs_handlers, | ||
}, | ||
}; | ||
|
||
/** Encrypted syslog recursion marker */ | ||
static int syslogs_entered; | ||
|
||
/** | ||
* Print a character to encrypted syslog console | ||
* | ||
* @v character Character to be printed | ||
*/ | ||
static void syslogs_putchar ( int character ) { | ||
int rc; | ||
|
||
/* Ignore if we are already mid-logging */ | ||
if ( syslogs_entered ) | ||
return; | ||
|
||
/* Fill line buffer */ | ||
if ( line_putchar ( &syslogs_line, character ) == 0 ) | ||
return; | ||
|
||
/* Guard against re-entry */ | ||
syslogs_entered = 1; | ||
|
||
/* Send log message */ | ||
if ( ( rc = xfer_printf ( &syslogs, "<%d>ipxe: %s\n", | ||
SYSLOG_PRIORITY ( SYSLOG_DEFAULT_FACILITY, | ||
syslogs_severity ), | ||
syslogs_buffer ) ) != 0 ) { | ||
DBG ( "SYSLOGS could not send log message: %s\n", | ||
strerror ( rc ) ); | ||
} | ||
|
||
/* Clear re-entry flag */ | ||
syslogs_entered = 0; | ||
} | ||
|
||
/** Encrypted syslog console driver */ | ||
struct console_driver syslogs_console __console_driver = { | ||
.putchar = syslogs_putchar, | ||
.disabled = 1, | ||
.usage = CONSOLE_SYSLOGS, | ||
}; | ||
|
||
/****************************************************************************** | ||
* | ||
* Settings | ||
* | ||
****************************************************************************** | ||
*/ | ||
|
||
/** Encrypted syslog server setting */ | ||
struct setting syslogs_setting __setting ( SETTING_MISC ) = { | ||
.name = "syslogs", | ||
.description = "Encrypted syslog server", | ||
.tag = DHCP_EB_SYSLOGS_SERVER, | ||
.type = &setting_type_string, | ||
}; | ||
|
||
/** | ||
* Apply encrypted syslog settings | ||
* | ||
* @ret rc Return status code | ||
*/ | ||
static int apply_syslogs_settings ( void ) { | ||
static char *old_server; | ||
char *server; | ||
struct interface *socket; | ||
int len; | ||
int rc; | ||
|
||
/* Fetch log server */ | ||
len = fetch_string_setting_copy ( NULL, &syslogs_setting, &server ); | ||
if ( len < 0 ) { | ||
rc = len; | ||
goto err_fetch_server; | ||
} | ||
|
||
/* Do nothing unless log server has changed */ | ||
if ( ( ( server == NULL ) && ( old_server == NULL ) ) || | ||
( ( server != NULL ) && ( old_server != NULL ) && | ||
( strcmp ( server, old_server ) == 0 ) ) ) { | ||
rc = 0; | ||
goto out_no_change; | ||
} | ||
free ( old_server ); | ||
old_server = NULL; | ||
|
||
/* Reset encrypted syslog connection */ | ||
syslogs_console.disabled = 1; | ||
intf_restart ( &syslogs, 0 ); | ||
|
||
/* Do nothing unless we have a log server */ | ||
if ( ! server ) { | ||
DBG ( "SYSLOGS has no log server\n" ); | ||
rc = 0; | ||
goto out_no_server; | ||
} | ||
|
||
/* Add TLS filter */ | ||
if ( ( rc = add_tls ( &syslogs, server, &socket ) ) != 0 ) { | ||
DBG ( "SYSLOGS cannot create TLS filter: %s\n", | ||
strerror ( rc ) ); | ||
goto err_add_tls; | ||
} | ||
|
||
/* Connect to log server */ | ||
if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, | ||
(( struct sockaddr *) &logserver ), | ||
server, NULL ) ) != 0 ) { | ||
DBG ( "SYSLOGS cannot connect to log server: %s\n", | ||
strerror ( rc ) ); | ||
goto err_open_named_socket; | ||
} | ||
DBG ( "SYSLOGS using log server %s\n", server ); | ||
|
||
/* Record log server */ | ||
old_server = server; | ||
server = NULL; | ||
|
||
/* Success */ | ||
rc = 0; | ||
|
||
err_open_named_socket: | ||
err_add_tls: | ||
out_no_server: | ||
out_no_change: | ||
free ( server ); | ||
err_fetch_server: | ||
return rc; | ||
} | ||
|
||
/** Encrypted syslog settings applicator */ | ||
struct settings_applicator syslogs_applicator __settings_applicator = { | ||
.apply = apply_syslogs_settings, | ||
}; |