mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
Subject: Support to bind accepted socket to device on Linux
AG: move new member to end of info, allow info member even on nonsupporting platform, document requires root, apply only to listen skt before we drop root, add -k to test server to allow testing
This commit is contained in:
parent
156363f3de
commit
393b38aed9
6 changed files with 71 additions and 1 deletions
|
@ -862,6 +862,40 @@ This allocation is only deleted / replaced when the connection accesses a
|
|||
URL region with a different protocol (or the default protocols[0] if no
|
||||
CALLBACK area matches it).
|
||||
|
||||
@section BINDTODEV SO_BIND_TO_DEVICE
|
||||
|
||||
The .bind_iface flag in the context / vhost creation struct lets you
|
||||
declare that you want all traffic for listen and transport on that
|
||||
vhost to be strictly bound to the network interface named in .iface.
|
||||
|
||||
This Linux-only feature requires SO_BIND_TO_DEVICE, which in turn
|
||||
requires CAP_NET_RAW capability... root has this capability.
|
||||
|
||||
However this feature needs to apply the binding also to accepted
|
||||
sockets during normal operation, which implies the server must run
|
||||
the whole time as root.
|
||||
|
||||
You can avoid this by using the Linux capabilities feature to have
|
||||
the unprivileged user inherit just the CAP_NET_RAW capability.
|
||||
|
||||
You can confirm this with the test server
|
||||
|
||||
|
||||
```
|
||||
$ sudo /usr/local/bin/libwebsockets-test-server -u agreen -i eno1 -k
|
||||
```
|
||||
|
||||
The part that ensures the capability is inherited by the unprivileged
|
||||
user is
|
||||
|
||||
```
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
info.caps[0] = CAP_NET_RAW;
|
||||
info.count_caps = 1;
|
||||
#endif
|
||||
```
|
||||
|
||||
|
||||
@section dim Dimming webpage when connection lost
|
||||
|
||||
The lws test plugins' html provides useful feedback on the webpage about if it
|
||||
|
|
|
@ -355,6 +355,10 @@ lws_create_vhost(struct lws_context *context,
|
|||
vh->name = info->vhost_name;
|
||||
|
||||
vh->iface = info->iface;
|
||||
#if !defined(LWS_WITH_ESP8266) && !defined(LWS_WITH_ESP32) && !defined(OPTEE_TA) && !defined(WIN32)
|
||||
vh->bind_iface = info->bind_iface;
|
||||
#endif
|
||||
|
||||
for (vh->count_protocols = 0;
|
||||
info->protocols[vh->count_protocols].callback;
|
||||
vh->count_protocols++)
|
||||
|
|
|
@ -1991,6 +1991,17 @@ struct lws_context_creation_info {
|
|||
/**< CONTEXT: count of Linux capabilities in .caps[]. 0 means
|
||||
* no capabilities will be inherited from root (the default) */
|
||||
#endif
|
||||
int bind_iface;
|
||||
/**< VHOST: nonzero to strictly bind sockets to the interface name in
|
||||
* .iface (eg, "eth2"), using SO_BIND_TO_DEVICE.
|
||||
*
|
||||
* Requires SO_BINDTODEVICE support from your OS and CAP_NET_RAW
|
||||
* capability.
|
||||
*
|
||||
* Notice that common things like access network interface IP from
|
||||
* your local machine use your lo / loopback interface and will be
|
||||
* disallowed by this.
|
||||
*/
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
|
|
|
@ -255,6 +255,17 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (vhost->bind_iface) {
|
||||
lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface);
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
|
||||
strlen(vhost->iface)) < 0) {
|
||||
lwsl_warn("Failed to bind to device %s\n", vhost->iface);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disable Nagle */
|
||||
optval = 1;
|
||||
#if defined (__sun)
|
||||
|
|
|
@ -854,6 +854,9 @@ struct lws_vhost {
|
|||
struct lws *lserv_wsi;
|
||||
const char *name;
|
||||
const char *iface;
|
||||
#if !defined(LWS_WITH_ESP8266) && !defined(LWS_WITH_ESP32) && !defined(OPTEE_TA) && !defined(WIN32)
|
||||
int bind_iface;
|
||||
#endif
|
||||
const struct lws_protocols *protocols;
|
||||
void **protocol_vh_privs;
|
||||
const struct lws_protocol_vhost_options *pvo;
|
||||
|
|
|
@ -222,7 +222,7 @@ int main(int argc, char **argv)
|
|||
info.port = 7681;
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:", options, NULL);
|
||||
n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:k", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
|
@ -260,6 +260,13 @@ int main(int argc, char **argv)
|
|||
interface_name[(sizeof interface_name) - 1] = '\0';
|
||||
iface = interface_name;
|
||||
break;
|
||||
case 'k':
|
||||
info.bind_iface = 1;
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
info.caps[0] = CAP_NET_RAW;
|
||||
info.count_caps = 1;
|
||||
#endif
|
||||
break;
|
||||
case 'c':
|
||||
close_testing = 1;
|
||||
fprintf(stderr, " Close testing mode -- closes on "
|
||||
|
|
Loading…
Add table
Reference in a new issue