mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-28 23:38:31 +00:00
Make fixes and improvements
- Invent iso8601us() for faster timestamps - Improve --strace descriptions of sigset_t - Rebuild the Landlock Make bootstrap binary - Introduce MODE=sysv for non-Windows builds - Permit OFD fcntl() locks under pledge(flock) - redbean can now protect your kernel from ddos - Have vfork() fallback to sys_fork() not fork() - Change kmalloc() to not die when out of memory - Improve documentation for some termios functions - Rewrite putenv() and friends to conform to POSIX - Fix linenoise + strace verbosity issue on Windows - Fix regressions in our ability to show backtraces - Change redbean SetHeader() to no-op if value is nil - Improve fcntl() so SQLite locks work in non-WAL mode - Remove some unnecessary work during fork() on Windows - Create redbean-based SSL reverse proxy for IPv4 TurfWar - Fix ape/apeinstall.sh warning when using non-bash shells - Add ProgramTrustedIp(), and IsTrustedIp() APIs to redbean - Support $PWD, $UID, $GID, and $EUID in command interpreter - Introduce experimental JTqFpD APE prefix for non-Windows builds - Invent blackhole daemon for firewalling IP addresses via UNIX named socket - Add ProgramTokenBucket(), AcquireToken(), and CountTokens() APIs to redbean
This commit is contained in:
parent
648bf6555c
commit
f7ff77d865
209 changed files with 3818 additions and 998 deletions
|
@ -90,7 +90,7 @@
|
|||
|
||||
#define PORT 8080 // default server listening port
|
||||
#define CPUS 64 // number of cpus to actually use
|
||||
#define WORKERS 100 // size of http client thread pool
|
||||
#define WORKERS 500 // size of http client thread pool
|
||||
#define SUPERVISE_MS 1000 // how often to stat() asset files
|
||||
#define KEEPALIVE_MS 60000 // max time to keep idle conn open
|
||||
#define MELTALIVE_MS 2000 // panic keepalive under heavy load
|
||||
|
@ -108,7 +108,7 @@
|
|||
#define BATCH_MAX 64 // max claims to insert per transaction
|
||||
#define NICK_MAX 40 // max length of user nickname string
|
||||
#define TB_INTERVAL 1000 // millis between token replenishes
|
||||
#define TB_CIDR 22 // token bucket cidr specificity
|
||||
#define TB_CIDR 24 // token bucket cidr specificity
|
||||
#define SOCK_MAX 100 // max length of socket queue
|
||||
#define MSG_BUF 512 // small response lookaside
|
||||
|
||||
|
@ -233,6 +233,14 @@ struct Asset {
|
|||
char lastmodified[32];
|
||||
};
|
||||
|
||||
struct Blackhole {
|
||||
struct sockaddr_un addr;
|
||||
int fd;
|
||||
} g_blackhole = {{
|
||||
AF_UNIX,
|
||||
"/var/run/blackhole.sock",
|
||||
}};
|
||||
|
||||
// cli flags
|
||||
bool g_integrity;
|
||||
bool g_daemonize;
|
||||
|
@ -248,6 +256,7 @@ atomic_int g_connections;
|
|||
nsync_note g_shutdown[3];
|
||||
|
||||
// whitebox metrics
|
||||
atomic_long g_banned;
|
||||
atomic_long g_accepts;
|
||||
atomic_long g_dbfails;
|
||||
atomic_long g_proxied;
|
||||
|
@ -401,6 +410,19 @@ int DbPrepare(sqlite3 *db, sqlite3_stmt **stmt, const char *sql) {
|
|||
return sqlite3_prepare_v2(db, sql, -1, stmt, 0);
|
||||
}
|
||||
|
||||
bool Blackhole(uint32_t ip) {
|
||||
char buf[4];
|
||||
WRITE32BE(buf, ip);
|
||||
if (sendto(g_blackhole.fd, buf, 4, 0, (struct sockaddr *)&g_blackhole.addr,
|
||||
sizeof(g_blackhole.addr)) == 4) {
|
||||
return true;
|
||||
} else {
|
||||
kprintf("error: sendto(/var/run/blackhole.sock) failed: %s\n",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// validates name registration validity
|
||||
bool IsValidNick(const char *s, size_t n) {
|
||||
size_t i;
|
||||
|
@ -674,10 +696,11 @@ void ServeStatusz(int client, char *outbuf) {
|
|||
g_messages / MAX(1, _timespec_sub(now, g_started).tv_sec));
|
||||
p = Statusz(p, "started", g_started.tv_sec);
|
||||
p = Statusz(p, "now", now.tv_sec);
|
||||
p = Statusz(p, "messages", g_messages);
|
||||
p = Statusz(p, "connections", g_connections);
|
||||
p = Statusz(p, "banned", g_banned);
|
||||
p = Statusz(p, "workers", g_workers);
|
||||
p = Statusz(p, "accepts", g_accepts);
|
||||
p = Statusz(p, "messages", g_messages);
|
||||
p = Statusz(p, "dbfails", g_dbfails);
|
||||
p = Statusz(p, "proxied", g_proxied);
|
||||
p = Statusz(p, "memfails", g_memfails);
|
||||
|
@ -759,8 +782,8 @@ void *ListenWorker(void *arg) {
|
|||
}
|
||||
if (!AddClient(&g_clients, &client, WaitFor(ACCEPT_DEADLINE_MS))) {
|
||||
++g_rejected;
|
||||
LOG("502 Accept Queue Full\n");
|
||||
Write(client.sock, "HTTP/1.1 502 Accept Queue Full\r\n"
|
||||
LOG("503 Accept Queue Full\n");
|
||||
Write(client.sock, "HTTP/1.1 503 Accept Queue Full\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
|
@ -834,6 +857,9 @@ void *HttpWorker(void *arg) {
|
|||
++g_messages;
|
||||
++g_worker[id].msgcount;
|
||||
|
||||
ipv6 = false;
|
||||
ip = clientip;
|
||||
|
||||
// get client address from frontend
|
||||
if (HasHeader(kHttpXForwardedFor)) {
|
||||
if (!IsLoopbackIp(clientip) && //
|
||||
|
@ -861,17 +887,21 @@ void *HttpWorker(void *arg) {
|
|||
ip = clientip;
|
||||
++g_unproxied;
|
||||
}
|
||||
|
||||
ksnprintf(ipbuf, sizeof(ipbuf), "%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16,
|
||||
ip >> 8, ip);
|
||||
|
||||
if ((tok = AcquireToken(g_tok.b, ip, TB_CIDR)) < 64) {
|
||||
if (tok > 8) {
|
||||
if (!ipv6 && (tok = AcquireToken(g_tok.b, ip, TB_CIDR)) < 32) {
|
||||
if (tok > 4) {
|
||||
LOG("%s rate limiting client\n", ipbuf, msg->version);
|
||||
Write(client.sock, "HTTP/1.1 429 Too Many Requests\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
"429 Too Many Requests\n");
|
||||
} else {
|
||||
Blackhole(ip);
|
||||
++g_banned;
|
||||
}
|
||||
++g_ratelimits;
|
||||
break;
|
||||
|
@ -1113,8 +1143,8 @@ void *HttpWorker(void *arg) {
|
|||
sent = write(client.sock, outbuf, p - outbuf);
|
||||
break;
|
||||
} else {
|
||||
LOG("%s: 502 Claims Queue Full\n", ipbuf);
|
||||
Write(client.sock, "HTTP/1.1 502 Claims Queue Full\r\n"
|
||||
LOG("%s: 503 Claims Queue Full\n", ipbuf);
|
||||
Write(client.sock, "HTTP/1.1 503 Claims Queue Full\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
|
@ -1793,6 +1823,15 @@ int main(int argc, char *argv[]) {
|
|||
CHECK_EQ(0, chdir("/opt/turfwar"));
|
||||
putenv("TMPDIR=/opt/turfwar/tmp");
|
||||
|
||||
if ((g_blackhole.fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1) {
|
||||
kprintf("error: socket(AF_UNIX) failed: %s\n", strerror(errno));
|
||||
_Exit(3);
|
||||
}
|
||||
if (!Blackhole(0)) {
|
||||
kprintf("redbean isn't able to protect your kernel from level 4 ddos\n");
|
||||
kprintf("please run the blackholed program, see https://justine.lol/\n");
|
||||
}
|
||||
|
||||
// the power to serve
|
||||
if (g_daemonize) {
|
||||
if (fork() > 0) _Exit(0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue