mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
syslog: make the destination port configurable
The port was frozen at 514 in the call that opens the connection, so a collector listening anywhere else was simply out of reach, and plenty do, because 514 is privileged and containerised collectors usually get a high port instead. Working around it meant putting a proxy in front, which then rewrites the source address and hides which device actually sent the line. Add `syslog port <n>`. The default stays 514, so nothing changes for an existing configuration. Setting it tears the connection down and builds a new one, the same dance the address already does, because uip_udp_new() freezes the port into the connection. The value is parsed here rather than through atoi_short(), which reports "no digits" but not overflow: 65540 would quietly wrap to 4 and we would open a connection to a port nobody asked for. Checking before each multiply keeps it in 16-bit arithmetic. Zero then covers all three ways to be wrong - no digits, past 65535, or an explicit "0", which is not a port either. Whitelist the new command in config.js as well, next to `syslog ip`, or the line is dropped without a word when the configuration is saved and the setting quietly fails to survive a reboot. The dedup entry has to precede the general `^syslog\b` one, otherwise it would deduplicate against `syslog on`. itoa_short() is new: itoa() only handles a byte and print_short() prints hex, so there was no way to show a port as a decimal number. Kept separate from itoa() rather than widening it, because every existing caller passes a byte and would start paying for 16-bit divisions it does not need. The scratch variables for the parser live in xdata. Locals there would take internal RAM, and this image has none left: data ends at 0x77, the overlay occupies 0x78-0x7f and the stack starts at 0x80. Measured: no module's DSEG grew.
This commit is contained in:
1 parent
9d4e531306
commit
cb43b3cbd6
6 files changed
+101
-4
No files matched your search
+65
-2
@@ -65,6 +65,13 @@ __xdata char save_cmd;
|
|||||||
|
|
||||||
__xdata uint8_t ip[4];
|
__xdata uint8_t ip[4];
|
||||||
|
|
||||||
|
/* Scratch for parse_syslog()'s port parser, in xdata: locals here would take
|
||||||
|
* internal RAM the linker has none of. */
|
||||||
|
__xdata uint16_t syslog_port_scratch;
|
||||||
|
__xdata uint8_t syslog_port_idx;
|
||||||
|
__xdata uint8_t syslog_port_digit;
|
||||||
|
__xdata uint8_t syslog_port_was_on;
|
||||||
|
|
||||||
// These variables combined create a Fixed-capacity vector/bounded buffer.
|
// These variables combined create a Fixed-capacity vector/bounded buffer.
|
||||||
// `N_WORDS`: The total number of command arguments that can be tracked.
|
// `N_WORDS`: The total number of command arguments that can be tracked.
|
||||||
// `cmd_words_len` stores the number of arguments found inside `cmd_buffer`
|
// `cmd_words_len` stores the number of arguments found inside `cmd_buffer`
|
||||||
@@ -1411,6 +1418,7 @@ void parse_syslog(void)
|
|||||||
if (syslog_state.enabled) {
|
if (syslog_state.enabled) {
|
||||||
print_string("enabled, sending to ");
|
print_string("enabled, sending to ");
|
||||||
print_ip(syslog_state.server_ip);
|
print_ip(syslog_state.server_ip);
|
||||||
|
write_char(':'); itoa_short(syslog_state.server_port);
|
||||||
write_char('\n');
|
write_char('\n');
|
||||||
} else {
|
} else {
|
||||||
print_string("disabled\n");
|
print_string("disabled\n");
|
||||||
@@ -1439,11 +1447,66 @@ void parse_syslog(void)
|
|||||||
} else {
|
} else {
|
||||||
print_string("Invalid IP address\n");
|
print_string("Invalid IP address\n");
|
||||||
}
|
}
|
||||||
|
} else if (cmd_compare(1, "port")) {
|
||||||
|
if (cmd_words_len < 3) { // no additional argument -> print current port
|
||||||
|
print_string("Current syslog port: ");
|
||||||
|
itoa_short(syslog_state.server_port); write_char('\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Parsed here rather than with atoi_short(), which reports "no
|
||||||
|
* digits" but not overflow - 65540 would quietly wrap to 4 and we
|
||||||
|
* would open a connection to a port nobody asked for. Checking
|
||||||
|
* before each multiply keeps this in 16-bit arithmetic. */
|
||||||
|
syslog_port_scratch = 0;
|
||||||
|
syslog_port_idx = cmd_words_b[2];
|
||||||
|
for (;;) {
|
||||||
|
/* Plain comparisons instead of isnumber() in the loop
|
||||||
|
* condition, and nested ifs instead of || and &&: either form
|
||||||
|
* makes SDCC park a boolean in the bit area, and an image
|
||||||
|
* carrying LACP and STP as well is one bit short of needing a
|
||||||
|
* third byte of it - which would push everything up and stop
|
||||||
|
* the link. */
|
||||||
|
syslog_port_digit = cmd_buffer[syslog_port_idx];
|
||||||
|
if (syslog_port_digit < '0')
|
||||||
|
break;
|
||||||
|
if (syslog_port_digit > '9')
|
||||||
|
break;
|
||||||
|
syslog_port_digit -= '0';
|
||||||
|
if (syslog_port_scratch > 6553) {
|
||||||
|
syslog_port_scratch = 0; /* too large - reject below */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (syslog_port_scratch == 6553) {
|
||||||
|
if (syslog_port_digit > 5) {
|
||||||
|
syslog_port_scratch = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syslog_port_scratch = syslog_port_scratch * 10 + syslog_port_digit;
|
||||||
|
syslog_port_idx++;
|
||||||
|
}
|
||||||
|
/* Zero covers all three ways to be wrong: no digits at all, a value
|
||||||
|
* past 65535, and an explicit "0", which is not a port either. */
|
||||||
|
if (!syslog_port_scratch) {
|
||||||
|
print_string("Invalid port\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* The port is frozen into the connection by uip_udp_new(), so
|
||||||
|
* changing it has to tear the connection down and build a new one -
|
||||||
|
* same dance as setting the address above. */
|
||||||
|
syslog_port_was_on = syslog_state.enabled;
|
||||||
|
if (syslog_port_was_on)
|
||||||
|
syslog_stop();
|
||||||
|
print_string("Setting new syslog port.\n");
|
||||||
|
syslog_state.server_port = syslog_port_scratch;
|
||||||
|
if (syslog_port_was_on)
|
||||||
|
syslog_start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
print_string("Error: syslog [on|off|ip [ip-address]]\n");
|
print_string("Error: syslog [on|off|ip [ip-address]|port [number]]\n");
|
||||||
print_string(" on/off enables or disables syslog, ip sets the syslog server IP address\n");
|
print_string(" on/off enables or disables syslog, ip sets the syslog server IP address,\n");
|
||||||
|
print_string(" port sets the destination UDP port (default 514)\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const conf_cmds = [
|
|||||||
/^netmask\s+(\d{1,3}\.){3}\d{1,3}$/,
|
/^netmask\s+(\d{1,3}\.){3}\d{1,3}$/,
|
||||||
/^syslog\s+(on|off)$/,
|
/^syslog\s+(on|off)$/,
|
||||||
/^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/,
|
/^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/,
|
||||||
|
/^syslog\s+port\s+\d{1,5}$/,
|
||||||
/^passwd\s+\S+$/,
|
/^passwd\s+\S+$/,
|
||||||
/^vlan\s+\d{1,4}\s+d$/,
|
/^vlan\s+\d{1,4}\s+d$/,
|
||||||
/^vlan\s+\d{1,4}\s+mgmt$/,
|
/^vlan\s+\d{1,4}\s+mgmt$/,
|
||||||
@@ -32,6 +33,7 @@ const conf_overwrite = [
|
|||||||
/^gw\b/,
|
/^gw\b/,
|
||||||
/^netmask\b/,
|
/^netmask\b/,
|
||||||
/^syslog\s+ip\b/,
|
/^syslog\s+ip\b/,
|
||||||
|
/^syslog\s+port\b/,
|
||||||
/^syslog\b/,
|
/^syslog\b/,
|
||||||
/^passwd\b/,
|
/^passwd\b/,
|
||||||
/^vlan\s+\d{1,4}\s+mgmt$/,
|
/^vlan\s+\d{1,4}\s+mgmt$/,
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ void print_long(uint32_t a);
|
|||||||
void print_short(uint16_t a);
|
void print_short(uint16_t a);
|
||||||
void print_byte(uint8_t a);
|
void print_byte(uint8_t a);
|
||||||
void itoa(uint8_t v);
|
void itoa(uint8_t v);
|
||||||
|
void itoa_short(uint16_t v);
|
||||||
void print_sfr_data(void);
|
void print_sfr_data(void);
|
||||||
void print_phy_data(void);
|
void print_phy_data(void);
|
||||||
void print_cmd_prompt(void);
|
void print_cmd_prompt(void);
|
||||||
|
|||||||
@@ -278,6 +278,32 @@ void itoa(uint8_t v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Same as itoa(), one decade wider: enough for a port number. Kept separate
|
||||||
|
* rather than widening itoa() itself, because every existing caller passes a
|
||||||
|
* byte and would start paying for 16-bit divisions it does not need. */
|
||||||
|
void itoa_short(uint16_t v)
|
||||||
|
{
|
||||||
|
uint8_t t = v / 10000;
|
||||||
|
uint8_t print_zeros = t;
|
||||||
|
|
||||||
|
if (print_zeros)
|
||||||
|
write_char('0' + t);
|
||||||
|
t = (v / 1000) % 10;
|
||||||
|
print_zeros |= t;
|
||||||
|
if (print_zeros)
|
||||||
|
write_char('0' + t);
|
||||||
|
t = (v / 100) % 10;
|
||||||
|
print_zeros |= t;
|
||||||
|
if (print_zeros)
|
||||||
|
write_char('0' + t);
|
||||||
|
t = (v / 10) % 10;
|
||||||
|
print_zeros |= t;
|
||||||
|
if (print_zeros)
|
||||||
|
write_char('0' + t);
|
||||||
|
write_char('0' + (v % 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void print_string(__code char *p)
|
void print_string(__code char *p)
|
||||||
{
|
{
|
||||||
while (*p)
|
while (*p)
|
||||||
|
|||||||
@@ -27,20 +27,22 @@ void syslog_init(void) __banked
|
|||||||
state.readptr = 0;
|
state.readptr = 0;
|
||||||
state.line_available = 0;
|
state.line_available = 0;
|
||||||
state.server_ip[0] = 0; state.server_ip[1] = 0; state.server_ip[2] = 0; state.server_ip[3] = 0;// Default to 0.0.0.0
|
state.server_ip[0] = 0; state.server_ip[1] = 0; state.server_ip[2] = 0; state.server_ip[3] = 0;// Default to 0.0.0.0
|
||||||
|
state.server_port = SYSLOG_PORT_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syslog_start(void) __banked
|
void syslog_start(void) __banked
|
||||||
{
|
{
|
||||||
if (state.syslog_conn == 0) {
|
if (state.syslog_conn == 0) {
|
||||||
uip_ipaddr(server_ip, state.server_ip[0], state.server_ip[1], state.server_ip[2], state.server_ip[3]);
|
uip_ipaddr(server_ip, state.server_ip[0], state.server_ip[1], state.server_ip[2], state.server_ip[3]);
|
||||||
state.syslog_conn = uip_udp_new(&server_ip, HTONS(514));
|
state.syslog_conn = uip_udp_new(&server_ip, HTONS(state.server_port));
|
||||||
if (state.syslog_conn == 0) {
|
if (state.syslog_conn == 0) {
|
||||||
print_string_newline_no_syslog("Failed to create a new UDP client");
|
print_string_newline_no_syslog("Failed to create a new UDP client");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
print_string_newline_no_syslog("Started syslog to IP ");
|
print_string_newline_no_syslog("Started syslog to IP ");
|
||||||
itoa(state.server_ip[0]); write_char('.'); itoa(state.server_ip[1]); write_char('.');
|
itoa(state.server_ip[0]); write_char('.'); itoa(state.server_ip[1]); write_char('.');
|
||||||
itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]); write_char('\n');
|
itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]);
|
||||||
|
write_char(':'); itoa_short(state.server_port); write_char('\n');
|
||||||
state.enabled = 1;
|
state.enabled = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -5,12 +5,15 @@
|
|||||||
|
|
||||||
#define LOGBUF_SIZE 512
|
#define LOGBUF_SIZE 512
|
||||||
|
|
||||||
|
#define SYSLOG_PORT_DEFAULT 514
|
||||||
|
|
||||||
struct syslog_state {
|
struct syslog_state {
|
||||||
uint8_t enabled;
|
uint8_t enabled;
|
||||||
uint8_t line_available;
|
uint8_t line_available;
|
||||||
uint16_t writeptr ;
|
uint16_t writeptr ;
|
||||||
uint16_t readptr;
|
uint16_t readptr;
|
||||||
uint8_t server_ip[4];
|
uint8_t server_ip[4];
|
||||||
|
uint16_t server_port;
|
||||||
|
|
||||||
struct uip_udp_conn *syslog_conn;
|
struct uip_udp_conn *syslog_conn;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in new issue
Block a user