depracating --bandwidth commands
Some checks failed
Build-extra / build-gcc (push) Has been cancelled
Build-extra / build-clang (push) Has been cancelled
Build / build (push) Has been cancelled
Check-C / scan-build (push) Has been cancelled
Check-C / cppcheck (push) Has been cancelled
Check-C / codeql-cpp (push) Has been cancelled
Check-Profiles / profile-checks (push) Has been cancelled
Check-Python / codeql-python (push) Has been cancelled
Codespell / codespell (push) Has been cancelled
Test / test-main (push) Has been cancelled
Test / test-fs (push) Has been cancelled
Test / test-environment (push) Has been cancelled
Test / test-utils (push) Has been cancelled
Test / test-network (push) Has been cancelled

This commit is contained in:
netblue30 2026-07-04 06:50:58 -04:00
parent c4a99f41cc
commit dcbce5e9b9
8 changed files with 30 additions and 598 deletions

View file

@ -227,7 +227,6 @@ endif
$(INSTALL) -m 0755 -t $(DESTDIR)$(libdir)/firejail src/fbwrap/fbwrap
# plugins w/o read permission (non-dumpable)
$(INSTALL) -m 0711 -t $(DESTDIR)$(libdir)/firejail $(SBOX_APPS_NON_DUMPABLE)
$(INSTALL) -m 0711 -t $(DESTDIR)$(libdir)/firejail src/fshaper/fshaper.sh
$(INSTALL) -m 0644 -t $(DESTDIR)$(libdir)/firejail src/fnettrace/static-ip-map
ifeq ($(HAVE_CONTRIB_INSTALL),yes)
# contrib scripts

View file

@ -1,397 +0,0 @@
/*
* Copyright (C) 2014-2026 Firejail Authors
*
* This file is part of firejail project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <net/if.h>
#include "firejail.h"
//***********************************
// interface bandwidth linked list
//***********************************
typedef struct ifbw_t {
struct ifbw_t *next;
char *txt;
} IFBW;
IFBW *ifbw = NULL;
#if 0
static void ifbw_print(void) {
IFBW *ptr = ifbw;
while (ptr) {
printf("#%s#\n", ptr->txt);
ptr = ptr->next;
}
}
#endif
static void ifbw_add(IFBW *ptr) {
assert(ptr);
if (ifbw != NULL)
ptr->next = ifbw;
ifbw = ptr;
}
IFBW *ifbw_find(const char *dev) {
assert(dev);
int len = strlen(dev);
assert(len);
if (ifbw == NULL)
return NULL;
IFBW *ptr = ifbw;
while (ptr) {
if (strncmp(ptr->txt, dev, len) == 0 && ptr->txt[len] == ':')
return ptr;
ptr = ptr->next;
}
return NULL;
}
void ifbw_remove(IFBW *r) {
if (ifbw == NULL)
return;
// remove the first element
if (ifbw == r) {
ifbw = ifbw->next;
return;
}
// walk the list
IFBW *ptr = ifbw->next;
IFBW *prev = ifbw;
while (ptr) {
if (ptr == r) {
prev->next = ptr->next;
return;
}
prev = ptr;
ptr = ptr->next;
}
return;
}
int fibw_count(void) {
int rv = 0;
IFBW *ptr = ifbw;
while (ptr) {
rv++;
ptr = ptr->next;
}
return rv;
}
//***********************************
// run file handling
//***********************************
static void bandwidth_create_run_file(pid_t pid) {
char *fname;
if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1)
errExit("asprintf");
// create an empty file and set mod and ownership
// if the file already exists, do nothing
FILE *fp = fopen(fname, "wxe");
free(fname);
if (!fp) {
if (errno == EEXIST)
return;
fprintf(stderr, "Error: cannot create bandwidth file\n");
exit(1);
}
SET_PERMS_STREAM(fp, 0, 0, 0644);
fclose(fp);
}
void network_set_run_file(pid_t pid) {
char *fname;
if (asprintf(&fname, "%s/%d-netmap", RUN_FIREJAIL_NETWORK_DIR, (int) pid) == -1)
errExit("asprintf");
// create an empty file and set mod and ownership
FILE *fp = fopen(fname, "we");
if (fp) {
if (cfg.bridge0.configured)
fprintf(fp, "%s:%s\n", cfg.bridge0.dev, cfg.bridge0.devsandbox);
if (cfg.bridge1.configured)
fprintf(fp, "%s:%s\n", cfg.bridge1.dev, cfg.bridge1.devsandbox);
if (cfg.bridge2.configured)
fprintf(fp, "%s:%s\n", cfg.bridge2.dev, cfg.bridge2.devsandbox);
if (cfg.bridge3.configured)
fprintf(fp, "%s:%s\n", cfg.bridge3.dev, cfg.bridge3.devsandbox);
SET_PERMS_STREAM(fp, 0, 0, 0644);
fclose(fp);
}
else {
fprintf(stderr, "Error: cannot create network map file\n");
exit(1);
}
free(fname);
}
static void read_bandwidth_file(pid_t pid) {
assert(ifbw == NULL);
char *fname;
if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1)
errExit("asprintf");
FILE *fp = fopen(fname, "re");
if (fp) {
char buf[1024];
while (fgets(buf, 1024,fp)) {
// remove '\n'
char *ptr = strchr(buf, '\n');
if (ptr)
*ptr = '\0';
if (strlen(buf) == 0)
continue;
// create a new IFBW entry
IFBW *ifbw_new = malloc(sizeof(IFBW));
if (!ifbw_new)
errExit("malloc");
memset(ifbw_new, 0, sizeof(IFBW));
ifbw_new->txt = strdup(buf);
if (!ifbw_new->txt)
errExit("strdup");
// add it to the linked list
ifbw_add(ifbw_new);
}
fclose(fp);
}
free(fname);
}
static void write_bandwidth_file(pid_t pid) {
if (ifbw == NULL)
return; // nothing to do
char *fname;
if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1)
errExit("asprintf");
FILE *fp = fopen(fname, "we");
if (fp) {
IFBW *ptr = ifbw;
while (ptr) {
if (fprintf(fp, "%s\n", ptr->txt) < 0)
goto errout;
ptr = ptr->next;
}
fclose(fp);
free(fname);
}
else
goto errout;
return;
errout:
fprintf(stderr, "Error: cannot write bandwidth file %s\n", fname);
exit(1);
}
//***********************************
// add or remove interfaces
//***********************************
// remove interface from run file
void bandwidth_remove(pid_t pid, const char *dev) {
bandwidth_create_run_file(pid);
// read bandwidth file
read_bandwidth_file(pid);
// find the element and remove it
IFBW *elem = ifbw_find(dev);
if (elem) {
ifbw_remove(elem);
write_bandwidth_file(pid) ;
}
// remove the file if there are no entries in the list
if (ifbw == NULL)
delete_bandwidth_run_file(pid);
}
// add interface to run file
void bandwidth_set(pid_t pid, const char *dev, int down, int up) {
// create bandwidth directory & file in case they are not in the filesystem yet
bandwidth_create_run_file(pid);
// create the new text entry
char *txt;
if (asprintf(&txt, "%s: RX %dKB/s, TX %dKB/s", dev, down, up) == -1)
errExit("asprintf");
// read bandwidth file
read_bandwidth_file(pid);
// look for an existing entry and replace the text
IFBW *ptr = ifbw_find(dev);
if (ptr) {
assert(ptr->txt);
free(ptr->txt);
ptr->txt = txt;
}
// ... or add a new entry
else {
IFBW *ifbw_new = malloc(sizeof(IFBW));
if (!ifbw_new)
errExit("malloc");
memset(ifbw_new, 0, sizeof(IFBW));
ifbw_new->txt = txt;
// add it to the linked list
ifbw_add(ifbw_new);
}
write_bandwidth_file(pid) ;
}
//***********************************
// command execution
//***********************************
void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, int up) {
EUID_ASSERT();
enter_network_namespace(pid);
//************************
// build command
//************************
char *devname = NULL;
if (dev) {
// read network map file
char *fname;
if (asprintf(&fname, "%s/%d-netmap", RUN_FIREJAIL_NETWORK_DIR, (int) pid) == -1)
errExit("asprintf");
FILE *fp = fopen(fname, "re");
if (!fp) {
fprintf(stderr, "Error: cannot read network map file %s\n", fname);
exit(1);
}
char buf[1024];
int len = strlen(dev);
while (fgets(buf, 1024, fp)) {
// remove '\n'
char *ptr = strchr(buf, '\n');
if (ptr)
*ptr = '\0';
if (*buf == '\0')
break;
if (strncmp(buf, dev, len) == 0 && buf[len] == ':') {
devname = strdup(buf + len + 1);
if (!devname)
errExit("strdup");
// double-check device name
size_t i;
for (i = 0; devname[i]; i++) {
if (isalnum((unsigned char) devname[i]) == 0 &&
devname[i] != '-') {
fprintf(stderr, "Error: name of network device is invalid\n");
exit(1);
}
}
// check device in namespace
if (if_nametoindex(devname) == 0) {
fprintf(stderr, "Error: cannot find network device %s\n", devname);
exit(1);
}
break;
}
}
free(fname);
fclose(fp);
}
// set run file
if (strcmp(command, "set") == 0) {
if (devname == NULL) {
fprintf(stderr, "Error: cannot find a %s interface inside the sandbox\n", dev);
exit(1);
}
bandwidth_set(pid, devname, down, up);
}
else if (strcmp(command, "clear") == 0) {
if (devname == NULL) {
fprintf(stderr, "Error: cannot find a %s interface inside the sandbox\n", dev);
exit(1);
}
bandwidth_remove(pid, devname);
}
else assert(strcmp(command, "status") == 0);
// build fshaper.sh command
char *cmd = NULL;
if (devname) {
if (strcmp(command, "set") == 0) {
if (asprintf(&cmd, "%s/firejail/fshaper.sh --%s %s %d %d",
LIBDIR, command, devname, down, up) == -1)
errExit("asprintf");
}
else {
if (asprintf(&cmd, "%s/firejail/fshaper.sh --%s %s",
LIBDIR, command, devname) == -1)
errExit("asprintf");
}
}
else {
if (asprintf(&cmd, "%s/firejail/fshaper.sh --%s", LIBDIR, command) == -1)
errExit("asprintf");
}
assert(cmd);
//************************
// build command
//************************
char *arg[4];
arg[0] = "/bin/sh";
arg[1] = "-c";
arg[2] = cmd;
arg[3] = NULL;
clearenv();
sbox_exec_v(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, arg);
// it will never get here!!
}

View file

@ -413,6 +413,7 @@ int sandbox(void* sandbox_arg);
void start_application(int no_sandbox, int fd, char *set_sandbox_status) __attribute__((noreturn));
// network_main.c
void network_set_run_file(pid_t pid);
void net_configure_sandbox_ip(Bridge *br);
void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child);
void net_check_cfg(void);
@ -722,10 +723,6 @@ void check_netns(const char *nsname);
void netns(const char *nsname);
void netns_mounts(const char *nsname);
// bandwidth.c
void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, int up) __attribute__((noreturn));
void network_set_run_file(pid_t pid);
// fs_etc.c
char *fs_etc_build(char *str);
void fs_resolvconf(void);

View file

@ -506,67 +506,6 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
}
#ifdef HAVE_NETWORK
else if (strncmp(argv[i], "--bandwidth=", 12) == 0) {
if (checkcfg(CFG_NETWORK)) {
logargs(argc, argv);
// extract the command
if ((i + 1) == argc) {
fprintf(stderr, "Error: command expected after --bandwidth option\n");
exit(1);
}
char *cmd = argv[i + 1];
if (strcmp(cmd, "status") && strcmp(cmd, "clear") && strcmp(cmd, "set")) {
fprintf(stderr, "Error: invalid --bandwidth command.\nValid commands: set, clear, status.\n");
exit(1);
}
// extract network name
char *dev = NULL;
int down = 0;
int up = 0;
if (strcmp(cmd, "set") == 0 || strcmp(cmd, "clear") == 0) {
// extract device name
if ((i + 2) == argc) {
fprintf(stderr, "Error: network name expected after --bandwidth %s option\n", cmd);
exit(1);
}
dev = argv[i + 2];
// check device name
if (if_nametoindex(dev) == 0) {
fprintf(stderr, "Error: network device %s not found\n", dev);
exit(1);
}
// extract bandwidth
if (strcmp(cmd, "set") == 0) {
if ((i + 4) >= argc) {
fprintf(stderr, "Error: invalid --bandwidth set command\n");
exit(1);
}
down = atoi(argv[i + 3]);
if (down < 0) {
fprintf(stderr, "Error: invalid download speed\n");
exit(1);
}
up = atoi(argv[i + 4]);
if (up < 0) {
fprintf(stderr, "Error: invalid upload speed\n");
exit(1);
}
}
}
// extract pid or sandbox name
pid_t pid = require_pid(argv[i] + 12);
bandwidth_pid(pid, cmd, dev, down, up);
}
else
exit_err_feature(argv[i], CFG_NETWORK);
exit(0);
}
else if (strncmp(argv[i], "--netfilter.print=", 18) == 0) {
// extract pid or sandbox name
pid_t pid = require_pid(argv[i] + 18);

View file

@ -26,6 +26,34 @@
#include <stdarg.h>
#include <sys/wait.h>
void network_set_run_file(pid_t pid) {
char *fname;
if (asprintf(&fname, "%s/%d-netmap", RUN_FIREJAIL_NETWORK_DIR, (int) pid) == -1)
errExit("asprintf");
// create an empty file and set mod and ownership
FILE *fp = fopen(fname, "we");
if (fp) {
if (cfg.bridge0.configured)
fprintf(fp, "%s:%s\n", cfg.bridge0.dev, cfg.bridge0.devsandbox);
if (cfg.bridge1.configured)
fprintf(fp, "%s:%s\n", cfg.bridge1.dev, cfg.bridge1.devsandbox);
if (cfg.bridge2.configured)
fprintf(fp, "%s:%s\n", cfg.bridge2.dev, cfg.bridge2.devsandbox);
if (cfg.bridge3.configured)
fprintf(fp, "%s:%s\n", cfg.bridge3.dev, cfg.bridge3.devsandbox);
SET_PERMS_STREAM(fp, 0, 0, 0644);
fclose(fp);
}
else {
fprintf(stderr, "Error: cannot create network map file\n");
exit(1);
}
free(fname);
}
// configure bridge structure
// - extract ip address and mask from the bridge interface
static void net_configure_bridge(Bridge *br) {

View file

@ -104,7 +104,7 @@ static int pid_is_firejail(pid_t pid) {
// stats
"tree", "list", "top",
// network
"netstats", "bandwidth",
"netstats",
// etc
"help", "version",

View file

@ -1,78 +0,0 @@
#!/bin/bash
# This file is part of Firejail project
# Copyright (C) 2014-2026 Firejail Authors
# License GPL v2
TCFILE="$(PATH=/usr/sbin:/sbin:/run/current-system/sw/bin command -v tc)"
if [ -z "$TCFILE" ]; then
echo "Error: traffic control utility (tc) not found"
exit 1
fi
usage() {
echo "Usage:"
echo " fshaper.sh --status"
echo " fshaper.sh --clear device"
echo " fshaper.sh --set device download-speed upload-speed"
}
if [ "$1" = "--status" ]; then
$TCFILE -s qdisc ls
$TCFILE -s class ls
exit
fi
if [ "$1" = "--clear" ]; then
if [ $# -ne 2 ]; then
echo "Error: invalid command"
usage
exit
fi
DEV=$2
echo "Removing bandwidth limits"
$TCFILE qdisc del dev $DEV root 2> /dev/null > /dev/null
$TCFILE qdisc del dev $DEV ingress 2> /dev/null > /dev/null
exit
fi
if [ "$1" = "--set" ]; then
DEV=$2
echo "Removing bandwidth limit"
$TCFILE qdisc del dev $DEV ingress #2> /dev/null > /dev/null
if [ $# -ne 4 ]; then
echo "Error: missing parameters"
usage
exit
fi
DEV=$2
echo "Configuring interface $DEV "
IN=$3
IN=$((${IN} * 8))
echo "Download speed ${IN}kbps"
OUT=$4
OUT=$((${OUT} * 8))
echo "Upload speed ${OUT}kbps"
echo "cleaning limits"
$TCFILE qdisc del dev $DEV root 2> /dev/null > /dev/null
$TCFILE qdisc del dev $DEV ingress 2> /dev/null > /dev/null
echo "configuring tc ingress"
$TCFILE qdisc add dev $DEV handle ffff: ingress #2> /dev/null > /dev/null
$TCFILE filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src \
0.0.0.0/0 police rate ${IN}kbit burst 10k drop flowid :1 #2> /dev/null > /dev/null
echo "configuring tc egress"
$TCFILE qdisc add dev $DEV root tbf rate ${OUT}kbit latency 25ms burst 10k #2> /dev/null > /dev/null
exit
fi
echo "Error: missing parameters"
usage
exit 1

View file

@ -22,14 +22,6 @@ firejail {\-\-ls | \-\-get | \-\-put | \-\-cat} dir_or_filename
.RE
.PP
#endif
#ifdef HAVE_NETWORK
Network traffic shaping for an existing sandbox:
.PP
.RS
firejail \-\-bandwidth={name|pid} bandwidth-command
.RE
.PP
#endif
Monitoring:
.PP
.RS
@ -220,11 +212,6 @@ Note: When using both \fB\-\-appimage\fR and \fB\-\-profile\fR, it is recommende
to always specify the former before the latter, so that any \fB?HAS_APPIMAGE\fR
conditionals inside of the profile evaluate to true (see \fB?CONDITIONAL\fR in
firejail\-profile(5)).
#ifdef HAVE_NETWORK
.TP
\fB\-\-bandwidth=name|pid
Set bandwidth limits for the sandbox identified by name or PID, see \fBTRAFFIC SHAPING\fR section for more details.
#endif
.TP
\fB\-\-bind=filename1,filename2
Mount-bind filename1 on top of filename2. This option is only available when running as root.
@ -3975,49 +3962,6 @@ adduser \-\-shell /usr/bin/firejail username
Additional arguments passed to firejail executable upon login are declared in /etc/firejail/login.users file.
#ifdef HAVE_NETWORK
.SH TRAFFIC SHAPING
Network bandwidth is an expensive resource shared among all sandboxes running on a system.
Traffic shaping allows the user to increase network performance by controlling
the amount of data that flows into and out of the sandboxes.
Firejail implements a simple rate-limiting shaper based on Linux command tc.
The shaper works at sandbox level, and can be used only for sandboxes configured with new network namespaces.
Set rate-limits:
$ firejail \-\-bandwidth=name|pid set network download upload
Clear rate-limits:
$ firejail \-\-bandwidth=name|pid clear network
Status:
$ firejail \-\-bandwidth=name|pid status
where:
.br
name - sandbox name
.br
pid - sandbox pid
.br
network - network interface as used by \-\-net option
.br
download - download speed in KB/s (kilobyte per second)
.br
upload - upload speed in KB/s (kilobyte per second)
Example:
.br
$ firejail \-\-name=mybrowser \-\-net=eth0 /usr/bin/firefox &
.br
$ firejail \-\-bandwidth=mybrowser set eth0 80 20
.br
$ firejail \-\-bandwidth=mybrowser status
.br
$ firejail \-\-bandwidth=mybrowser clear eth0
#endif
.SH LICENSE
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
.PP