Commit Graph

134 Commits

Author SHA1 Message Date
Joris Vink cd9971247c Add seccomp syscall filtering to kore.
With this commit all Kore processes (minus the parent) are running
under seccomp.

The worker processes get the bare minimum allowed syscalls while each module
like curl, pgsql, etc will add their own filters to allow what they require.

New API functions:
    int kore_seccomp_filter(const char *name, void *filter, size_t len);

    Adds a filter into the seccomp system (must be called before
    seccomp is enabled).

New helpful macro:
    define KORE_SYSCALL_ALLOW(name)

    Allow the syscall with a given name, should be used in
    a sock_filter data structure.

New hooks:
    void kore_seccomp_hook(void);

    Called before seccomp is enabled, allows developers to add their
    own BPF filters into seccomp.
2019-09-25 14:31:20 +02:00
Joris Vink c3b2a8b2a2 fix NOHTTP builds 2019-09-20 09:37:02 +02:00
Joris Vink 8e858983bf python pgsql changes.
- decouple pgsql from the HTTP request allowing it to be used in other
  contexts as well (such as a task, etc).

- change names to dbsetup() and dbquery().

eg:

result = kore.dbquery("db", "select foo from bar")
2019-09-04 19:57:28 +02:00
Joris Vink 4a64b4f07b Improve curl timeout handling.
In case libcurl instructs us to call the timeout function as soon
as possible (timeout == 0 in curl_timeout), don't try to be clever
with a timeout value of 10ms.

Instead call the timeout function once we get back in the worker
event loop. This makes things a lot snappier as we don't depend
on epoll/kqueue waiting for io for 10ms (which actually isn't 10ms...).
2019-06-13 12:59:17 +02:00
Joris Vink 07fc7a9097 Improve HTTP processing.
If netwait is INFINITE but there are requests pending reduce the
netwait back down to 100ms so we keep processing them.
2019-05-29 15:27:44 +02:00
Joris Vink d2aa64df5c add kore_proctitle().
manipulates the argv+environ pointers to get a sensible process title
under linux / darwin.
2019-03-29 16:24:14 +01:00
Joris Vink e1766e74ba always capture worker processes exiting.
even if they terminated normally.
2019-03-22 10:29:14 +01:00
Joris Vink 4238431b9e Add worker_death_policy setting.
By default kore will restart worker processes if they terminate
unexpected. However in certain scenarios you may want to bring down
an entire kore instance if a worker process fails.

By setting worker_death_policy to "terminate" the Kore server will
completely stop if a worker exits unexpected.
2019-03-22 09:49:50 +01:00
Joris Vink 370041656e Get rid of WORKER_LOCK_TIMEOUT.
Instead let the workers send a message on the msg channel to each
other when they have given up the accept lock and it is now available
to be grabbed.
2019-03-21 14:03:11 +01:00
Joris Vink 8b0279879a rework timers so they fire more predictably.
this change also stops python coroutines from waking up very
late after their timeout has expired.

in filerefs, don't prime the timer until we actually have something
to expire, and kill the timer when the last ref drops.
2019-03-21 10:17:08 +01:00
Joris Vink 8afaac9fde log pid number of worker upon start. 2019-03-19 13:42:22 +01:00
Joris Vink eb9b7f7b14 explicitly include sys/types.h
some smaller libc variants do not include this from sys/param.h.
2019-03-06 09:29:46 +01:00
Joris Vink bf1e8e5ffb bump copyright to 2019 2019-02-22 16:57:28 +01:00
Joris Vink 66305e551a sig_recv is extern'd in kore.h 2019-02-11 14:01:25 +01:00
Joris Vink 8a8b08f1e6 use %u when logging worker_rlimit_nofiles 2019-02-11 14:00:28 +01:00
Joris Vink 73cdbd1a01 Let CRLs be reloadable via keymgr.
With these changes CRLs can be reloaded like certificates
by sending a SIGUSR1 to the parent process.

Track mtime on both certificate files and CRL files as well
and only submit them to the workers if this has changed.
2019-01-14 11:41:50 +01:00
Joris Vink 9aa0e95643 Rework accesslog handling.
Move away from the parent constantly hitting the disk for every
accesslog the workers are sending.

The workers will now write their own accesslogs to shared
memory before the parent will pick those up. The parent
will flush them to disk once every second or if they grow
larger then 1MB.

This removes the heavy penalty for having access logs
turned on when you are dealing with a large volume
of requests.
2018-12-22 09:25:00 +01:00
Joris Vink 2d8874dd2a change accept threshold default to 16. 2018-11-16 11:37:09 +01:00
Joris Vink 4e70636269 Reduce accept lock accept lockout time to 100ms. 2018-11-16 11:35:53 +01:00
Joris Vink baafa4897e Add -q flag.
If specified Kore will run quietly and only log important messages.
2018-11-15 16:01:37 +01:00
Joris Vink e2651889e0 Add asynchronous subprocess support.
This adds kore.proc to the python runtime allowing async processing
handling:

The kore.proc method takes the command to run and an optional timeout
parameter in milliseconds. If the process did not exit normally after
that amount of time a TimeoutError exception is raised.

For instance:

async def run(cmd):
	proc = kore.proc(cmd, 1000)

	try:
		await proc.send("hello")
		proc.close_stdin()
	except TimeoutError:
		proc.kill()

	retcode = await proc.reap()

	return retcode
2018-10-26 19:19:47 +02:00
Joris Vink 892814e353 Add kore_[parent|worker]_teardown().
If exists these functions are called when the worker is exiting
and when right before the parent exists.

Allows for cleanup code for applications if need to do cleanup on exit.
2018-10-23 21:46:34 +02:00
Joris Vink 4c35073232 Use number of cpu cores if no worker count is set. 2018-10-22 21:27:17 +02:00
Joris Vink 8be316ac0c Let kore_worker_make_busy() set next_lock. 2018-10-22 09:00:55 +02:00
Joris Vink 20a0103f1e Add async/await support for socket i/o in python.
This means you can now do things like:

	resp = await koresock.recv(1024)
	await koresock.send(resp)

directly from page handlers if they are defined as async.

Adds lots more to the python goo such as fatalx(), bind_unix(),
task_create() and socket_wrap().
2018-10-15 20:18:54 +02:00
Joris Vink 754ba47cc4 shuffle stuff around so we're not hitting bad juju. 2018-08-13 13:07:32 +02:00
Joris Vink 8d3f73bc71 call fatalx() instead of fatal() in certain cases. 2018-08-13 13:01:27 +02:00
Joris Vink cf92097bc2 log what dir we can't chdir() into. 2018-08-13 09:53:38 +02:00
Joris Vink a927acb7ee Add pledge support under OpenBSD.
All worker processes will now call pledge(2) after dropping
privileges (even if -rn was specified).

By default Kore will use the following promises:
	"stdio rpath inet error"

If your application requires more privileges, you can add more pledges
by setting them in your configuration using the 'pledge' directive:
	pledge dns wpath
2018-07-31 06:51:34 +02:00
Joris Vink 40a81a17ba remove kore_module_handle for NOHTTP=1 builds. 2018-07-17 14:28:43 +02:00
Joris Vink b957d26335 Let kore_worker_make_busy() not unlock solo workers 2018-07-13 21:04:59 +02:00
Joris Vink 02e7359970 Add kore_worker_make_busy().
Calling this from your page handler will cause your current worker
to give up the acceptlock (if it holds it).

This is particularly useful if you are about to run code that may block
a bit longer then you are comfortable with. Calling this will cause
the acceptlock to shuffle to another free worker which in turn makes
sure your application can keep accepting requests.
2018-07-11 18:00:16 +02:00
Joris Vink cffb7ec379 Allow on-the-fly reloading of certificates/keys.
This commit introduces the ability for the keymgr process
to reload the certificates/keys for domains when receiving
a SIGUSR1 signal.

The keymgr receives 2 new configuration options:
	- keymgr_root_path
		The root path where the keymgr will live.
		If -n is not specified when the application starts the
		keymgr process will chroot into here.

	- keymgr_runas_user
		The user the keymgr will drop privileges towards if
		-r was not specified.

All certfile and certkey configuration options are now relative to the
keymgr_root_path configuration setting.

The keymgr process will now also load the certificate for the domain
(rather then the workers) and submit these to the worker processes so
they can be reloaded when required.

Worker processes will refuse connections until the TLS configuration
for a given domain is completed (aka: the workers receive the certificate
for that domain).

Other changes:
	- client_certificates renamed to client_verify.
	- the chroot configuration option is now called root.
	- kore is a little more verbose if privsep options are missing.
	- filemaps are now relative to the root configuration option.
2018-07-11 09:44:29 +02:00
Joris Vink bf6c0e150f Let kore_worker_privdrop() take user and chroot.
This will make it easier when the keymgr gets its own user/chroot settings.
2018-07-11 06:53:51 +02:00
Joris Vink 5eb2160269 resolve filemap paths after workers chrooted.
otherwise the paths inside chrooted workers are incorrect.
2018-07-08 17:51:35 +02:00
Joris Vink 80f5425698 Add filemaps.
A filemap is a way of telling Kore to serve files from a directory
much like a traditional webserver can do.

Kore filemaps only handles files. Kore does not generate directory
indexes or deal with non-regular files.

The way files are sent to a client differs a bit per platform and
build options:

default:
  - mmap() backed file transfer due to TLS.

NOTLS=1
  - sendfile() under FreeBSD, macOS and Linux.
  - mmap() backed file for OpenBSD.

The opened file descriptors/mmap'd regions are cached and reused when
appropriate. If a file is no longer in use it will be closed and evicted
from the cache after 30 seconds.

New API's are available allowing developers to use these facilities via:
  void net_send_fileref(struct connection *, struct kore_fileref *);
  void http_response_fileref(struct http_request *, struct kore_fileref *);

Kore will attempt to match media types based on file extensions. A few
default types are built-in. Others can be added via the new "http_media_type"
configuration directive.
2018-06-28 13:27:44 +02:00
Joris Vink 9e12b2c6dd Use sigaction() for signals.
Don't duplicate signal setup code between parent and worker processes.
2018-05-25 20:49:02 +02:00
Joris Vink dd2dff2318 Rework HTTP and worker processes.
The HTTP layer used to make a copy of each incoming header and its
value for a request. Stop doing that and make HTTP headers zero-copy
all across the board.

This change comes with some api function changes, notably the
http_request_header() function which now takes a const char ** rather
than a char ** out pointer.

This commit also constifies several members of http_request, beware.

Additional rework how the worker processes deal with the accept lock.

Before:
	if a worker held the accept lock and it accepted a new connection
	it would release the lock for others and back off for 500ms before
	attempting to grab the lock again.

	This approach worked but under high load this starts becoming obvious.

Now:
	- workers not holding the accept lock and not having any connections
	  will wait less long before returning from kore_platform_event_wait().

	- workers not holding the accept lock will no longer blindly wait
	  an arbitrary amount in kore_platform_event_wait() but will look
	  at how long until the next lock grab is and base their timeout
	  on that.

	- if a worker its next_lock timeout is up and failed to grab the
	  lock it will try again in half the time again.

	- the worker process holding the lock will when releasing the lock
	  double check if it still has space for newer connections, if it does
	  it will keep the lock until it is full. This prevents the lock from
	  bouncing between several non busy worker processes all the time.

Additional fixes:

- Reduce the number of times we check the timeout list, only do it twice
  per second rather then every event tick.
- Fix solo worker count for TLS (we actually hold two processes, not one).
- Make sure we don't accidentally miscalculate the idle time causing new
  connections under heavy load to instantly drop.
- Swap from gettimeofday() to clock_gettime() now that MacOS caught up.
2018-02-14 13:48:49 +01:00
Joris Vink b3a48f3c15 Let http_request_limit matter.
Before http_request_limit just constrained the number of HTTP
requests we'd deal with in a single http_process_requests() call.

But it should really mean how many maximum HTTP requests are allowed
to be alive in the worker process before we start sending 503s back.

While here, drop the lock timeout for a worker to 100ms down from 500ms
and do not allow a worker to grab the accept lock if their HTTP request
queue is full.

This makes things much more pleasant memory wise as the http_request_pool
won't just grow over time.
2018-02-13 11:56:51 +01:00
Joris Vink 548348f553 2018 2018-01-20 22:51:06 +01:00
Joris Vink 2eab2f1ed7 Revert "automatically resolve existing symbols upon reload."
This isn't ready yet.
2017-08-31 17:11:24 +02:00
Joris Vink ed4ef22f1b automatically resolve existing symbols upon reload.
doing this allows us to get rid of the validator reload
and handler reload as well as fixing websocket runtime
callbacks which were never being resolved upon module reloads.
2017-08-31 16:26:36 +02:00
Joris Vink 59f7e85f45 Decouple pgsql from the http layer.
When the pgsql layer was introduced it was tightly coupled with the
http layer in order to make async work fluently.

The time has come to split these up and follow the same method we
used for tasks, allowing either http requests to be tied to a pgsql
data structure or a simple callback function.

This also reworks the internal queueing of pgsql requests until
connections to the db are available again.

The following API functions were changes:
	- kore_pgsql_query_init() -> kore_pgsql_setup()
		no longer takes an http_request parameter.
	- NEW kore_pgsql_init()
		must be called before operating on an kore_pgsql structure.
	- NEW kore_pgsql_bind_request()
		binds an http_request to a kore_pgsql data structure.
	- NEW kore_pgsql_bind_callback()
		binds a callback to a kore_pgsql data structure.

With all of this you can now build kore with PGSQL=1 NOHTTP=1.

The pgsql/ example has been updated to reflect these changes and
new features.
2017-03-24 12:53:07 +01:00
Joris Vink fb8035297d Allow workers to listen on different ports.
This commit allows worker processes to have individual listeners
not configured by the kore configuration.

If you do the following:
	- do not configure listeners in your .conf file
	- call kore_server_bind() in kore_worker_configure()

the workers will no longer fight over accept locks as the configured
ports no longer conflict with each other.

This allows me to create X amount of instances of a worker process that
are each individually accessible via unique ports.
2017-03-13 15:32:04 +01:00
Joris Vink 73fc58163d add warning + RAND_poll() to callback. 2017-02-27 21:31:09 -08:00
Joris Vink f57ca7dcc2 Let workers fetch entropy from keymgr.
At bootup and every 1800 seconds after that the worker processes will
ask the keymgr for new entropy that they will seed into their PRNG.

Additionally once received the worker calls RAND_poll() to grab
more entropy from the system to be mixed in.
2017-02-27 21:28:35 -08:00
Joris Vink ace8c4e80c Add asynchronous pgsql query support to python.
This commit adds the ability to use python "await" to suspend
execution of your page handler until the query sent to postgresql
has returned a result.

This is built upon the existing asynchrous query framework Kore had.

With this you can now write stuff like:

async def page(req):
	result = await req.pgsql("db", "SELECT name FROM table");
	req.response(200, json.dumps(result).encode("utf-8"))

The above code will fire off a query and suspend itself so Kore can
take care of business as usual until the query is successful at which
point Kore will jump back into the handler and resume.

This does not use threading, it's purely based on Python's excellent
coroutines and generators and Kore its built-in pgsql support.
2017-02-06 11:42:53 +01:00
Joris Vink 0c0a9371bd Change kore_preload() and kore_onload().
Renamed both of them:
	kore_preload -> kore_parent_configure
	kore_onload  -> kore_worker_configure

These functions will now always be called if they are defined in any module
regardless of your application being built as a single binary or not.
2017-02-01 17:12:11 +01:00
Joris Vink c06ecf1c70 Teach single binaries about SIGHUP.
Make sure kore_onload() and kore_preload() can be called
either in native or python runtime.
2017-01-26 13:26:55 +01:00
Joris Vink bbcdec82fc Add initial python support.
Based on work done by Stanislav Yudin.
2017-01-24 20:18:12 +01:00