return net_update_timeout(L, &net->tcp.tls_handshake_timeout, "net.tls_handshake_timeout");
}
+static int net_bpf_set(lua_State *L)
+{
+ int ret;
+ struct engine *engine = engine_luaget(L);
+ struct network *net = &engine->net;
+
+ if (lua_gettop(L) != 1 || lua_type(L, 1) != LUA_TINTEGER) {
+ format_error(L, "net.bpf_set(fd) takes one parameter: the open file descriptor of a loaded BPF program");
+ lua_error(L);
+ return 0;
+ }
+
+#if __linux__
+
+ int progfd = lua_tointeger(L, 1);
+ lua_pop(L, 1);
+
+ if (!network_set_bpf(net, progfd)) {
+ char errmsg[256] = {};
+ snprintf(errmsg, sizeof(errmsg), "failed to attach BPF program to some networks: %s", strerror(errno));
+ format_error(L, errmsg);
+ lua_error(L);
+ return 0;
+ }
+
+ lua_pushboolean(L, 1);
+ return 1;
+
+#endif
+
+ format_error(L, "BPF is not supported on this operating system");
+ lua_error(L);
+ return 0;
+}
+
+static int net_bpf_clear(lua_State *L)
+{
+ int ret;
+ struct engine *engine = engine_luaget(L);
+ struct network *net = &engine->net;
+
+ if (lua_gettop(L) != 0) {
+ format_error(L, "net.bpf_clear() does not take any parameters");
+ lua_error(L);
+ return 0;
+ }
+
+#if __linux__
+
+ network_clear_bpf(net);
+
+ lua_pushboolean(L, 1);
+ return 1;
+
+#endif
+
+ format_error(L, "BPF is not supported on this operating system");
+ lua_error(L);
+ return 0;
+}
+
int lib_net(lua_State *L)
{
static const luaL_Reg lib[] = {
{ "outgoing_v6", net_outgoing_v6 },
{ "tcp_in_idle", net_tcp_in_idle },
{ "tls_handshake_timeout", net_tls_handshake_timeout },
+ { "bpf_set", net_bpf_set },
+ { "bpf_clear", net_bpf_clear },
{ NULL, NULL }
};
register_lib(L, "net", lib);
}
}
}
+
+static int set_bpf_cb(const char *key, void *val, void *ext)
+{
+ endpoint_array_t *endpoints = (endpoint_array_t *)val;
+ assert(endpoints != NULL);
+ int *bpffd = (int *)ext;
+ assert(bpffd != NULL);
+
+ for (size_t i = 0; i < endpoints->len; i++) {
+ struct endpoint *endpoint = (struct endpoint *)endpoints->at[i];
+ uv_os_fd_t sockfd = -1;
+ if (endpoint->tcp != NULL) uv_fileno((const uv_handle_t *)endpoint->tcp, &sockfd);
+ if (endpoint->udp != NULL) uv_fileno((const uv_handle_t *)endpoint->udp, &sockfd);
+ assert(sockfd != -1);
+
+ if (setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_BPF, bpffd, sizeof(int)) != 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+bool network_set_bpf(struct network *net, int bpf_fd)
+{
+ if (!map_walk(&net->endpoints, set_bpf_cb, &bpf_fd)) {
+ network_clear_bpf(net);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int clear_bpf_cb(const char *key, void *val, void *ext)
+{
+ endpoint_array_t *endpoints = (endpoint_array_t *)val;
+ assert(endpoints != NULL);
+
+ for (size_t i = 0; i < endpoints->len; i++) {
+ struct endpoint *endpoint = (struct endpoint *)endpoints->at[i];
+ uv_os_fd_t sockfd = -1;
+ if (endpoint->tcp != NULL) uv_fileno((const uv_handle_t *)endpoint->tcp, &sockfd);
+ if (endpoint->udp != NULL) uv_fileno((const uv_handle_t *)endpoint->udp, &sockfd);
+ assert(sockfd != -1);
+
+ setsockopt(sockfd, SOL_SOCKET, SO_DETACH_BPF, NULL, 0);
+ }
+
+ return 1;
+}
+
+void network_clear_bpf(struct network *net)
+{
+ assert(map_walk(&net->endpoints, clear_bpf_cb, NULL));
+}
int network_set_tls_cert(struct network *net, const char *cert);
int network_set_tls_key(struct network *net, const char *key);
void network_new_hostname(struct network *net, struct engine *engine);
+bool network_set_bpf(struct network *net, int bpf_fd);
+void network_clear_bpf(struct network *net);