mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
httpd: keep the login sessions in bank 3
The web server's bank had no room left for the four sessions once the original firmware's more robust header handling came in. Picking a slot, checking a cookie and starting a session move to sessions.c in bank 3; httpd.c only calls session_init(), session_check() and session_new(). The random id is written straight into the reply, which drops gen_random_hex_chars() from bank 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
70f59b64f5
commit
a7db0ca8b6
5 files changed
+137
-72
No files matched your search
@@ -105,6 +105,7 @@ SRCS = \
|
|||||||
sfp.c \
|
sfp.c \
|
||||||
dns.c \
|
dns.c \
|
||||||
dns_cli.c \
|
dns_cli.c \
|
||||||
|
sessions.c \
|
||||||
ntp.c \
|
ntp.c \
|
||||||
ntp_cli.c \
|
ntp_cli.c \
|
||||||
syslog.c \
|
syslog.c \
|
||||||
|
|||||||
+6
-72
@@ -6,12 +6,12 @@
|
|||||||
#include "cmd_parser.h"
|
#include "cmd_parser.h"
|
||||||
#include "rtl837x_flash.h"
|
#include "rtl837x_flash.h"
|
||||||
#include "uip.h"
|
#include "uip.h"
|
||||||
|
#include "sessions.h"
|
||||||
#include "html_data.h"
|
#include "html_data.h"
|
||||||
|
|
||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#define SESSION_ID_LENGTH 12
|
|
||||||
#define SESSION_TIMEOUT_DEFAULT 200
|
#define SESSION_TIMEOUT_DEFAULT 200
|
||||||
|
|
||||||
/* Seconds of inactivity after which a session cookie stops validating.
|
/* Seconds of inactivity after which a session cookie stops validating.
|
||||||
@@ -75,13 +75,7 @@ __xdata uint8_t postbody_endpoint;
|
|||||||
__xdata uint16_t postbody_start;
|
__xdata uint16_t postbody_start;
|
||||||
|
|
||||||
__xdata char passwd[21];
|
__xdata char passwd[21];
|
||||||
/* Up to SESSIONS logins at once, each with its own cookie and its own
|
// Up to four logins at once, see sessions.c
|
||||||
* expiry. With a single one, logging in from a second browser (or a phone)
|
|
||||||
* ended the first browser's session at its next request. */
|
|
||||||
#define SESSIONS 4
|
|
||||||
__xdata char session_id[SESSIONS][SESSION_ID_LENGTH + 1];
|
|
||||||
__xdata uint32_t last_session_use[SESSIONS];
|
|
||||||
__xdata uint8_t session_slot;
|
|
||||||
__xdata uint8_t authenticated;
|
__xdata uint8_t authenticated;
|
||||||
__xdata uint32_t now;
|
__xdata uint32_t now;
|
||||||
|
|
||||||
@@ -114,33 +108,7 @@ void httpd_init(void) __banked
|
|||||||
// handling one, and nothing has set it yet at init time.
|
// handling one, and nothing has set it yet at init time.
|
||||||
for (uint8_t i = 0; i < UIP_CONNS; i++)
|
for (uint8_t i = 0; i < UIP_CONNS; i++)
|
||||||
uip_conns[i].appstate.tstate = TSTATE_CLOSED;
|
uip_conns[i].appstate.tstate = TSTATE_CLOSED;
|
||||||
for (session_slot = 0; session_slot < SESSIONS; session_slot++)
|
session_init();
|
||||||
session_id[session_slot][0] = NUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Leaf functions, so the compiler keeps their 32-bit scratch in the overlay
|
|
||||||
* rather than in internal RAM. */
|
|
||||||
static uint8_t session_stale(void)
|
|
||||||
{
|
|
||||||
if (now - last_session_use[session_slot] > session_timeout)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For a new login: a free or expired slot, else the least recently used. */
|
|
||||||
static void session_pick(void)
|
|
||||||
{
|
|
||||||
__xdata uint8_t i;
|
|
||||||
__xdata uint8_t oldest = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < SESSIONS; i++) {
|
|
||||||
session_slot = i;
|
|
||||||
if (!session_id[i][0] || session_stale())
|
|
||||||
return;
|
|
||||||
if (last_session_use[i] < last_session_use[oldest])
|
|
||||||
oldest = i;
|
|
||||||
}
|
|
||||||
session_slot = oldest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -375,40 +343,11 @@ __xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
|||||||
|
|
||||||
read_reg_timer(&now);
|
read_reg_timer(&now);
|
||||||
|
|
||||||
if (session) {
|
if (session)
|
||||||
for (session_slot = 0; session_slot < SESSIONS; session_slot++) {
|
session_check();
|
||||||
if (!session_id[session_slot][0])
|
|
||||||
continue;
|
|
||||||
if (session_stale()) {
|
|
||||||
dbg_string("Session expired\n");
|
|
||||||
session_id[session_slot][0] = NUL;
|
|
||||||
} else if (is_word_x(session, session_id[session_slot])) {
|
|
||||||
authenticated = 1;
|
|
||||||
last_session_use[session_slot] = now;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate random HEX-chars at the buffer location.
|
|
||||||
*/
|
|
||||||
void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
|
|
||||||
{
|
|
||||||
uint8_t i = 0;
|
|
||||||
while (bytes) {
|
|
||||||
if (!i)
|
|
||||||
get_random_32();
|
|
||||||
b[--bytes] = itohex(sfr_data[i]);
|
|
||||||
if (!bytes) { break; }
|
|
||||||
b[--bytes] = itohex(sfr_data[i] >> 4 | sfr_data[i] << 4);
|
|
||||||
i = (i + 1) & 0x3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 0: body incomplete, 1: configuration stored, 2: malformed */
|
/* 0: body incomplete, 1: configuration stored, 2: malformed */
|
||||||
static uint8_t config_take(void)
|
static uint8_t config_take(void)
|
||||||
{
|
{
|
||||||
@@ -710,14 +649,9 @@ static void run_login_body(__xdata uint8_t *body)
|
|||||||
if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) {
|
if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) {
|
||||||
dbg_string("Password accepted!\n");
|
dbg_string("Password accepted!\n");
|
||||||
read_reg_timer(&now);
|
read_reg_timer(&now);
|
||||||
session_pick();
|
|
||||||
last_session_use[session_slot] = now;
|
|
||||||
gen_random_hex_chars(session_id[session_slot], SESSION_ID_LENGTH);
|
|
||||||
session_id[session_slot][SESSION_ID_LENGTH] = NUL;
|
|
||||||
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
|
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
|
||||||
"Set-Cookie: session=");
|
"Set-Cookie: session=");
|
||||||
for (uint8_t i = 0; i < SESSION_ID_LENGTH; i++)
|
session_new();
|
||||||
outbuf[slen++] = session_id[session_slot][i];
|
|
||||||
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
|
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
dbg_string("Password invalid!\n");
|
dbg_string("Password invalid!\n");
|
||||||
|
|||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Login sessions of the web interface.
|
||||||
|
*
|
||||||
|
* Up to SESSIONS logins at once, each with its own cookie and its own expiry.
|
||||||
|
* With a single one, logging in from a second browser (or a phone) ended the
|
||||||
|
* first browser's session at its next request.
|
||||||
|
*
|
||||||
|
* This sits in bank 3: the web server's own bank is full, so httpd.c only
|
||||||
|
* calls in here. It shares three things with httpd.c: the cookie value it
|
||||||
|
* parsed (session), the time read for the request (now) and the result
|
||||||
|
* (authenticated); the reply is written to outbuf at slen.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma codeseg BANK3
|
||||||
|
#pragma constseg BANK3
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "sessions.h"
|
||||||
|
|
||||||
|
extern volatile __xdata uint8_t sfr_data[4];
|
||||||
|
extern __xdata uint16_t session_timeout;
|
||||||
|
extern __xdata uint32_t now;
|
||||||
|
extern __xdata uint8_t authenticated;
|
||||||
|
extern __xdata uint8_t * __xdata session;
|
||||||
|
extern __xdata uint8_t outbuf[];
|
||||||
|
extern __xdata uint16_t slen;
|
||||||
|
|
||||||
|
__xdata char session_id[SESSIONS][SESSION_ID_LENGTH + 1];
|
||||||
|
__xdata uint32_t last_session_use[SESSIONS];
|
||||||
|
|
||||||
|
static __xdata uint8_t ss_slot, ss_i, ss_oldest, ss_c;
|
||||||
|
|
||||||
|
static __code const char ss_hex[] = "0123456789abcdef";
|
||||||
|
/* What may follow a cookie value: ';' separates cookies in a Cookie header */
|
||||||
|
static __code const char ss_end[] = " \t:?=\n\r;";
|
||||||
|
|
||||||
|
/* Leaf function, so the compiler keeps its 32-bit scratch in the overlay
|
||||||
|
* rather than in internal RAM. */
|
||||||
|
static uint8_t ss_stale(void)
|
||||||
|
{
|
||||||
|
if (now - last_session_use[ss_slot] > session_timeout)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Whether the cookie value is the id of slot ss_slot */
|
||||||
|
static uint8_t ss_match(void)
|
||||||
|
{
|
||||||
|
for (ss_i = 0; ss_i < SESSION_ID_LENGTH; ss_i++) {
|
||||||
|
if (session[ss_i] != session_id[ss_slot][ss_i])
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ss_c = session[SESSION_ID_LENGTH];
|
||||||
|
if (!ss_c)
|
||||||
|
return 1;
|
||||||
|
for (ss_i = 0; ss_end[ss_i]; ss_i++) {
|
||||||
|
if (ss_c == ss_end[ss_i])
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_init(void) __banked
|
||||||
|
{
|
||||||
|
for (ss_slot = 0; ss_slot < SESSIONS; ss_slot++)
|
||||||
|
session_id[ss_slot][0] = NUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_check(void) __banked
|
||||||
|
{
|
||||||
|
for (ss_slot = 0; ss_slot < SESSIONS; ss_slot++) {
|
||||||
|
if (!session_id[ss_slot][0])
|
||||||
|
continue;
|
||||||
|
if (ss_stale()) {
|
||||||
|
session_id[ss_slot][0] = NUL;
|
||||||
|
} else if (ss_match()) {
|
||||||
|
authenticated = 1;
|
||||||
|
last_session_use[ss_slot] = now;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_new(void) __banked
|
||||||
|
{
|
||||||
|
/* A free or expired slot, else the least recently used */
|
||||||
|
ss_oldest = 0;
|
||||||
|
for (ss_slot = 0; ss_slot < SESSIONS; ss_slot++) {
|
||||||
|
if (!session_id[ss_slot][0] || ss_stale())
|
||||||
|
break;
|
||||||
|
if (last_session_use[ss_slot] < last_session_use[ss_oldest])
|
||||||
|
ss_oldest = ss_slot;
|
||||||
|
}
|
||||||
|
if (ss_slot == SESSIONS)
|
||||||
|
ss_slot = ss_oldest;
|
||||||
|
|
||||||
|
last_session_use[ss_slot] = now;
|
||||||
|
for (ss_i = 0; ss_i < SESSION_ID_LENGTH; ss_i++) {
|
||||||
|
if (!(ss_i & 7))
|
||||||
|
get_random_32();
|
||||||
|
ss_c = sfr_data[(ss_i >> 1) & 3];
|
||||||
|
if (ss_i & 1)
|
||||||
|
ss_c >>= 4;
|
||||||
|
session_id[ss_slot][ss_i] = ss_hex[ss_c & 0xf];
|
||||||
|
outbuf[slen++] = ss_hex[ss_c & 0xf];
|
||||||
|
}
|
||||||
|
session_id[ss_slot][SESSION_ID_LENGTH] = NUL;
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _SESSIONS_H_
|
||||||
|
#define _SESSIONS_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define SESSIONS 4
|
||||||
|
#define SESSION_ID_LENGTH 12
|
||||||
|
|
||||||
|
extern __xdata char session_id[SESSIONS][SESSION_ID_LENGTH + 1];
|
||||||
|
extern __xdata uint32_t last_session_use[SESSIONS];
|
||||||
|
|
||||||
|
/* No session at boot */
|
||||||
|
void session_init(void) __banked;
|
||||||
|
/* Sets authenticated if the cookie in session belongs to a live session */
|
||||||
|
void session_check(void) __banked;
|
||||||
|
/* Starts a session at now and writes its id to outbuf at slen */
|
||||||
|
void session_new(void) __banked;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -72,6 +72,8 @@ $(BUILDDIR)/test_lacp: test_lacp.c $(SRCROOT)/rtl837x_lacp.c | $(BUILDDIR)
|
|||||||
# this test carries the environment below them itself.
|
# this test carries the environment below them itself.
|
||||||
$(BUILDDIR)/test_httpd_tx: test_httpd_tx.c $(SRCROOT)/httpd/httpd.c $(SRCROOT)/uip/uip.c | $(BUILDDIR)
|
$(BUILDDIR)/test_httpd_tx: test_httpd_tx.c $(SRCROOT)/httpd/httpd.c $(SRCROOT)/uip/uip.c | $(BUILDDIR)
|
||||||
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||||
|
# the login sessions httpd.c calls into
|
||||||
|
$(BUILDDIR)/test_httpd_tx: $(SRCROOT)/sessions.c
|
||||||
|
|
||||||
# CPU VLAN initialization with full and reduced user-port ranges.
|
# CPU VLAN initialization with full and reduced user-port ranges.
|
||||||
$(BUILDDIR)/test_cpu_vlan_restricted: CFLAGS += -DMACHINE_MAX_PORT=7
|
$(BUILDDIR)/test_cpu_vlan_restricted: CFLAGS += -DMACHINE_MAX_PORT=7
|
||||||
|
|||||||
Reference in new issue
Block a user