diff options
-rw-r--r-- | Makefile.in | 7 | ||||
-rw-r--r-- | README.md | 13 | ||||
-rw-r--r-- | RELNOTES | 1 | ||||
-rw-r--r-- | etc/tcpserver.net | 27 | ||||
-rw-r--r-- | src/firejail/netfilter.c | 13 | ||||
-rw-r--r-- | src/firejail/usage.c | 2 | ||||
-rw-r--r-- | src/fnetfilter/main.c | 144 | ||||
-rw-r--r-- | src/man/firejail.txt | 23 | ||||
-rwxr-xr-x | test/fnetfilter/cmdline.exp | 37 | ||||
-rwxr-xr-x | test/fnetfilter/copy.exp | 52 | ||||
-rwxr-xr-x | test/fnetfilter/default.exp | 40 | ||||
-rwxr-xr-x | test/fnetfilter/fnetfilter.sh | 28 | ||||
-rw-r--r-- | test/fnetfilter/outlocked | 0 | ||||
-rwxr-xr-x | test/fnetfilter/template.exp | 82 | ||||
-rw-r--r-- | test/fnetfilter/test1.net | 19 | ||||
-rw-r--r-- | test/fnetfilter/test2.net | 19 | ||||
-rw-r--r-- | test/fnetfilter/test3.net | 1 | ||||
-rwxr-xr-x | test/network/netfilter-template.exp | 44 | ||||
-rwxr-xr-x | test/network/network.sh | 6 | ||||
-rw-r--r-- | test/network/tcpserver.c | 108 |
20 files changed, 633 insertions, 33 deletions
diff --git a/Makefile.in b/Makefile.in index 9334d8608..d11d537bc 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -276,10 +276,13 @@ test-fs: | |||
276 | test-fcopy: | 276 | test-fcopy: |
277 | cd test/fcopy; ./fcopy.sh | grep TESTING | 277 | cd test/fcopy; ./fcopy.sh | grep TESTING |
278 | 278 | ||
279 | test: test-profiles test-private-lib test-fcopy test-fs test-utils test-sysutils test-environment test-apps test-apps-x11 test-apps-x11-xorg test-filters test-arguments | 279 | test-fnetfilter: |
280 | cd test/fnetfilter; ./fnetfilter.sh | grep TESTING | ||
281 | |||
282 | test: test-profiles test-private-lib test-fcopy test-fnetfilter test-fs test-utils test-sysutils test-environment test-apps test-apps-x11 test-apps-x11-xorg test-filters test-arguments | ||
280 | echo "TEST COMPLETE" | 283 | echo "TEST COMPLETE" |
281 | 284 | ||
282 | test-travis: test-profiles test-fcopy test-fs test-utils test-sysutils test-environment test-filters test-arguments | 285 | test-travis: test-profiles test-fcopy test-fnetfilter test-fs test-utils test-sysutils test-environment test-filters test-arguments |
283 | echo "TEST COMPLETE" | 286 | echo "TEST COMPLETE" |
284 | 287 | ||
285 | ########################################## | 288 | ########################################## |
@@ -210,18 +210,27 @@ $ | |||
210 | --debug-private-lib | 210 | --debug-private-lib |
211 | Debug messages for --private-lib option. | 211 | Debug messages for --private-lib option. |
212 | 212 | ||
213 | --netfilter=filename,arg1,arg2,arg3 ... | ||
214 | This is the template version of the previous command. $ARG1, | ||
215 | $ARG2, $ARG3 ... in the firewall script are replaced with arg1, | ||
216 | arg2, arg3 ... passed on the command line. Up to 16 arguments | ||
217 | are supported. Example: | ||
218 | |||
219 | $ firejail --net=eth0 --ip=192.168.1.105 \ | ||
220 | --netfilter=/etc/firejail/tcpserver.net,5001 server-program | ||
221 | |||
213 | --netfilter.print=name|pid | 222 | --netfilter.print=name|pid |
214 | Print the firewall installed in the sandbox specified by name | 223 | Print the firewall installed in the sandbox specified by name |
215 | or PID. Example: | 224 | or PID. Example: |
216 | 225 | ||
217 | $ firejail --net=browser --net=eth0 --netfilter firefox & | 226 | $ firejail --name=browser --net=eth0 --netfilter firefox & |
218 | $ firejail --netfilter.print=browser | 227 | $ firejail --netfilter.print=browser |
219 | 228 | ||
220 | --netfilter6.print=name|pid | 229 | --netfilter6.print=name|pid |
221 | Print the IPv6 firewall installed in the sandbox specified by | 230 | Print the IPv6 firewall installed in the sandbox specified by |
222 | name or PID. Example: | 231 | name or PID. Example: |
223 | 232 | ||
224 | $ firejail --net=browser --net=eth0 --netfilter firefox & | 233 | $ firejail --name=browser --net=eth0 --netfilter firefox & |
225 | $ firejail --netfilter6.print=browser | 234 | $ firejail --netfilter6.print=browser |
226 | 235 | ||
227 | ````` | 236 | ````` |
@@ -27,6 +27,7 @@ firejail (0.9.51) baseline; urgency=low | |||
27 | * feature: profile build tool (--build) | 27 | * feature: profile build tool (--build) |
28 | * feature: --netfilter.print | 28 | * feature: --netfilter.print |
29 | * feature: --netfilter6.print | 29 | * feature: --netfilter6.print |
30 | * feature: netfilter template support | ||
30 | * new profiles: upstreamed many profiles from the following sources: | 31 | * new profiles: upstreamed many profiles from the following sources: |
31 | https://github.com/chiraag-nataraj/firejail-profiles, | 32 | https://github.com/chiraag-nataraj/firejail-profiles, |
32 | https://github.com/nyancat18/fe, | 33 | https://github.com/nyancat18/fe, |
diff --git a/etc/tcpserver.net b/etc/tcpserver.net new file mode 100644 index 000000000..e60404e6b --- /dev/null +++ b/etc/tcpserver.net | |||
@@ -0,0 +1,27 @@ | |||
1 | *filter | ||
2 | :INPUT DROP [0:0] | ||
3 | :FORWARD DROP [0:0] | ||
4 | :OUTPUT DROP [0:0] | ||
5 | |||
6 | ################################################################### | ||
7 | # Simple tcp filter template. $ARG1 is the port number. | ||
8 | # | ||
9 | # Usage: $ARG1 in this template is replaced by 5001 from command line below | ||
10 | # | ||
11 | # firejail --net=eth0 --ip=192.168.1.105 --netfilter=/etc/firejail/tcpserver.net,5001 server-program | ||
12 | # | ||
13 | ################################################################### | ||
14 | |||
15 | # allow server traffic | ||
16 | -A INPUT -p tcp --dport $ARG1 -m state --state NEW,ESTABLISHED -j ACCEPT | ||
17 | -A OUTPUT -p tcp --sport $ARG1 -m state --state ESTABLISHED -j ACCEPT | ||
18 | |||
19 | # allow incoming ping | ||
20 | -A INPUT -p icmp --icmp-type echo-request -j ACCEPT | ||
21 | -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT | ||
22 | |||
23 | # allow outgoing DNS | ||
24 | -A OUTPUT -p udp --dport 53 -j ACCEPT | ||
25 | -A INPUT -p udp --sport 53 -j ACCEPT | ||
26 | |||
27 | COMMIT | ||
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c index e1d0edd01..dd4009a2e 100644 --- a/src/firejail/netfilter.c +++ b/src/firejail/netfilter.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <sys/wait.h> | 24 | #include <sys/wait.h> |
25 | #include <fcntl.h> | 25 | #include <fcntl.h> |
26 | 26 | ||
27 | |||
28 | void check_netfilter_file(const char *fname) { | 27 | void check_netfilter_file(const char *fname) { |
29 | EUID_ASSERT(); | 28 | EUID_ASSERT(); |
30 | 29 | ||
@@ -44,7 +43,6 @@ void check_netfilter_file(const char *fname) { | |||
44 | free(tmp); | 43 | free(tmp); |
45 | } | 44 | } |
46 | 45 | ||
47 | |||
48 | void netfilter(const char *fname) { | 46 | void netfilter(const char *fname) { |
49 | // find iptables command | 47 | // find iptables command |
50 | struct stat s; | 48 | struct stat s; |
@@ -150,6 +148,16 @@ void netfilter_print(pid_t pid, int ipv6) { | |||
150 | } | 148 | } |
151 | free(comm); | 149 | free(comm); |
152 | 150 | ||
151 | // check privileges for non-root users | ||
152 | uid_t uid = getuid(); | ||
153 | if (uid != 0) { | ||
154 | uid_t sandbox_uid = pid_get_uid(pid); | ||
155 | if (uid != sandbox_uid) { | ||
156 | fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n"); | ||
157 | exit(1); | ||
158 | } | ||
159 | } | ||
160 | |||
153 | // check network namespace | 161 | // check network namespace |
154 | char *name; | 162 | char *name; |
155 | if (asprintf(&name, "/run/firejail/network/%d-netmap", pid) == -1) | 163 | if (asprintf(&name, "/run/firejail/network/%d-netmap", pid) == -1) |
@@ -196,4 +204,3 @@ void netfilter_print(pid_t pid, int ipv6) { | |||
196 | 204 | ||
197 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, iptables, "-vL"); | 205 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, iptables, "-vL"); |
198 | } | 206 | } |
199 | |||
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index f1581e847..89ea4ccca 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -122,7 +122,7 @@ void usage(void) { | |||
122 | printf(" --net=ethernet_interface - enable network namespaces and connect to this\n"); | 122 | printf(" --net=ethernet_interface - enable network namespaces and connect to this\n"); |
123 | printf("\tEthernet interface.\n"); | 123 | printf("\tEthernet interface.\n"); |
124 | printf(" --net=none - enable a new, unconnected network namespace.\n"); | 124 | printf(" --net=none - enable a new, unconnected network namespace.\n"); |
125 | printf(" --netfilter[=filename] - enable firewall.\n"); | 125 | printf(" --netfilter[=filename,arg1,arg2,arg3 ...] - enable firewall.\n"); |
126 | printf(" --netfilter.print=name|pid - print the firewall.\n"); | 126 | printf(" --netfilter.print=name|pid - print the firewall.\n"); |
127 | printf(" --netfilter6=filename - enable IPv6 firewall.\n"); | 127 | printf(" --netfilter6=filename - enable IPv6 firewall.\n"); |
128 | printf(" --netfilter6.print=name|pid - print the IPv6 firewall.\n"); | 128 | printf(" --netfilter6.print=name|pid - print the IPv6 firewall.\n"); |
diff --git a/src/fnetfilter/main.c b/src/fnetfilter/main.c index 67ab31832..723c1ac32 100644 --- a/src/fnetfilter/main.c +++ b/src/fnetfilter/main.c | |||
@@ -20,8 +20,12 @@ | |||
20 | #include "../include/common.h" | 20 | #include "../include/common.h" |
21 | 21 | ||
22 | #define MAXBUF 4098 | 22 | #define MAXBUF 4098 |
23 | #define MAXARGS 16 | ||
24 | static char *args[MAXARGS] = {0}; | ||
25 | static int argcnt = 0; | ||
23 | int arg_quiet = 0; | 26 | int arg_quiet = 0; |
24 | 27 | ||
28 | |||
25 | static char *default_filter = | 29 | static char *default_filter = |
26 | "*filter\n" | 30 | "*filter\n" |
27 | ":INPUT DROP [0:0]\n" | 31 | ":INPUT DROP [0:0]\n" |
@@ -29,7 +33,7 @@ static char *default_filter = | |||
29 | ":OUTPUT ACCEPT [0:0]\n" | 33 | ":OUTPUT ACCEPT [0:0]\n" |
30 | "-A INPUT -i lo -j ACCEPT\n" | 34 | "-A INPUT -i lo -j ACCEPT\n" |
31 | "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" | 35 | "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" |
32 | "# echo replay is handled by -m state RELATED/ESTABLISHED below\n" | 36 | "# echo replay is handled by -m state RELATED/ESTABLISHED above\n" |
33 | "#-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT\n" | 37 | "#-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT\n" |
34 | "-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT\n" | 38 | "-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT\n" |
35 | "-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT\n" | 39 | "-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT\n" |
@@ -46,6 +50,111 @@ static void usage(void) { | |||
46 | printf("\tfnetfilter netfilter-command destination-file\n"); | 50 | printf("\tfnetfilter netfilter-command destination-file\n"); |
47 | } | 51 | } |
48 | 52 | ||
53 | |||
54 | static void copy(const char *src, const char *dest) { | ||
55 | FILE *fp1 = fopen(src, "r"); | ||
56 | if (!fp1) { | ||
57 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", src); | ||
58 | exit(1); | ||
59 | } | ||
60 | |||
61 | FILE *fp2 = fopen(dest, "w"); | ||
62 | if (!fp2) { | ||
63 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", dest); | ||
64 | exit(1); | ||
65 | } | ||
66 | |||
67 | char buf[MAXBUF]; | ||
68 | while (fgets(buf, MAXBUF, fp1)) | ||
69 | fprintf(fp2, "%s", buf); | ||
70 | |||
71 | fclose(fp1); | ||
72 | fclose(fp2); | ||
73 | } | ||
74 | |||
75 | static void process_template(char *src, const char *dest) { | ||
76 | char *arg_start = strchr(src, ','); | ||
77 | assert(arg_start); | ||
78 | *arg_start = '\0'; | ||
79 | arg_start++; | ||
80 | if (*arg_start == '\0') { | ||
81 | fprintf(stderr, "Error fnetfilter: you need to provide at least on argument\n"); | ||
82 | exit(1); | ||
83 | } | ||
84 | |||
85 | // extract the arguments from command line | ||
86 | char *token = strtok(arg_start, ","); | ||
87 | while (token) { | ||
88 | // look for abnormal things | ||
89 | int len = strlen(token); | ||
90 | if (strcspn(token, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) { | ||
91 | fprintf(stderr, "Error fnetfilter: invalid argument in netfilter command\n"); | ||
92 | exit(1); | ||
93 | } | ||
94 | args[argcnt] = token; | ||
95 | argcnt++; | ||
96 | token = strtok(NULL, ","); | ||
97 | } | ||
98 | #if 0 | ||
99 | { | ||
100 | printf("argcnt %d\n", argcnt); | ||
101 | int i; | ||
102 | for (i = 0; i < argcnt; i++) | ||
103 | printf("%s\n", args[i]); | ||
104 | } | ||
105 | #endif | ||
106 | |||
107 | // open the files | ||
108 | FILE *fp1 = fopen(src, "r"); | ||
109 | if (!fp1) { | ||
110 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", src); | ||
111 | exit(1); | ||
112 | } | ||
113 | |||
114 | FILE *fp2 = fopen(dest, "w"); | ||
115 | if (!fp2) { | ||
116 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", dest); | ||
117 | exit(1); | ||
118 | } | ||
119 | |||
120 | int line = 0; | ||
121 | char buf[MAXBUF]; | ||
122 | while (fgets(buf, MAXBUF, fp1)) { | ||
123 | line++; | ||
124 | char *ptr = buf; | ||
125 | while (*ptr != '\0') { | ||
126 | if (*ptr != '$') | ||
127 | fputc(*ptr, fp2); | ||
128 | else { | ||
129 | // parsing | ||
130 | int index = 0; | ||
131 | int rv = sscanf(ptr, "$ARG%u", &index) ; | ||
132 | if (rv != 1) { | ||
133 | fprintf(stderr, "Error fnetfilter: invalid template argument on line %d\n", line); | ||
134 | exit(1); | ||
135 | } | ||
136 | |||
137 | // print argument | ||
138 | if (index < 1 || index > argcnt) { | ||
139 | fprintf(stderr, "Error fnetfilter: $ARG%d on line %d was not defined\n", index, line); | ||
140 | exit(1); | ||
141 | } | ||
142 | fprintf(fp2, "%s", args[index - 1]); | ||
143 | |||
144 | // march to the end of argument | ||
145 | ptr += 4; | ||
146 | while (isdigit(*ptr)) | ||
147 | ptr++; | ||
148 | ptr--; | ||
149 | } | ||
150 | ptr++; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | fclose(fp1); | ||
155 | fclose(fp2); | ||
156 | } | ||
157 | |||
49 | int main(int argc, char **argv) { | 158 | int main(int argc, char **argv) { |
50 | #if 0 | 159 | #if 0 |
51 | { | 160 | { |
@@ -61,7 +170,7 @@ printf("\n"); | |||
61 | if (quiet && strcmp(quiet, "yes") == 0) | 170 | if (quiet && strcmp(quiet, "yes") == 0) |
62 | arg_quiet = 1; | 171 | arg_quiet = 1; |
63 | 172 | ||
64 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | 173 | if (argc > 1 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0)) { |
65 | usage(); | 174 | usage(); |
66 | return 0; | 175 | return 0; |
67 | } | 176 | } |
@@ -75,6 +184,12 @@ printf("\n"); | |||
75 | char *command = (argc == 3)? argv[1]: NULL; | 184 | char *command = (argc == 3)? argv[1]: NULL; |
76 | //printf("command %s\n", command); | 185 | //printf("command %s\n", command); |
77 | //printf("destfile %s\n", destfile); | 186 | //printf("destfile %s\n", destfile); |
187 | // destfile is a real filename | ||
188 | int len = strlen(destfile); | ||
189 | if (strcspn(destfile, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) { | ||
190 | fprintf(stderr, "Error fnetfilter: invalid destination file in netfilter command\n"); | ||
191 | exit(1); | ||
192 | } | ||
78 | 193 | ||
79 | // handle default config (command = NULL, destfile) | 194 | // handle default config (command = NULL, destfile) |
80 | if (command == NULL) { | 195 | if (command == NULL) { |
@@ -88,28 +203,11 @@ printf("\n"); | |||
88 | fclose(fp); | 203 | fclose(fp); |
89 | } | 204 | } |
90 | else { | 205 | else { |
91 | // copy the file | 206 | if (strrchr(command, ',')) |
92 | FILE *fp1 = fopen(command, "r"); | 207 | process_template(command, destfile); |
93 | if (!fp1) { | 208 | else |
94 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", command); | 209 | copy(command, destfile); |
95 | exit(1); | ||
96 | } | ||
97 | |||
98 | FILE *fp2 = fopen(destfile, "w"); | ||
99 | if (!fp2) { | ||
100 | fprintf(stderr, "Error fnetfilter: cannot open %s\n", destfile); | ||
101 | exit(1); | ||
102 | } | ||
103 | |||
104 | char buf[MAXBUF]; | ||
105 | while (fgets(buf, MAXBUF, fp1)) | ||
106 | fprintf(fp2, "%s", buf); | ||
107 | |||
108 | fclose(fp1); | ||
109 | fclose(fp2); | ||
110 | } | 210 | } |
111 | 211 | ||
112 | |||
113 | printf("fnetfilter running\n"); | ||
114 | return 0; | 212 | return 0; |
115 | } | 213 | } |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index bf27c07ad..d9000fd5e 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -937,13 +937,32 @@ is a desktop client firewall that disable access to local network. Example: | |||
937 | $ firejail --netfilter=/etc/firejail/nolocal.net \\ | 937 | $ firejail --netfilter=/etc/firejail/nolocal.net \\ |
938 | .br | 938 | .br |
939 | --net=eth0 firefox | 939 | --net=eth0 firefox |
940 | |||
941 | |||
942 | |||
943 | |||
944 | .TP | ||
945 | \fB\-\-netfilter=filename,arg1,arg2,arg3 ... | ||
946 | This is the template version of the previous command. $ARG1, $ARG2, $ARG3 ... in the firewall script | ||
947 | are replaced with arg1, arg2, arg3 ... passed on the command line. Up to 16 arguments are supported. | ||
948 | Example: | ||
949 | .br | ||
950 | |||
951 | .br | ||
952 | $ firejail --net=eth0 --ip=192.168.1.105 \\ | ||
953 | .br | ||
954 | --netfilter=/etc/firejail/tcpserver.net,5001 server-program | ||
955 | .br | ||
956 | |||
957 | |||
958 | |||
940 | .TP | 959 | .TP |
941 | \fB\-\-netfilter.print=name|pid | 960 | \fB\-\-netfilter.print=name|pid |
942 | Print the firewall installed in the sandbox specified by name or PID. Example: | 961 | Print the firewall installed in the sandbox specified by name or PID. Example: |
943 | .br | 962 | .br |
944 | 963 | ||
945 | .br | 964 | .br |
946 | $ firejail --net=browser --net=eth0 --netfilter firefox & | 965 | $ firejail --name=browser --net=eth0 --netfilter firefox & |
947 | .br | 966 | .br |
948 | $ firejail --netfilter.print=browser | 967 | $ firejail --netfilter.print=browser |
949 | 968 | ||
@@ -959,7 +978,7 @@ Print the IPv6 firewall installed in the sandbox specified by name or PID. Examp | |||
959 | .br | 978 | .br |
960 | 979 | ||
961 | .br | 980 | .br |
962 | $ firejail --net=browser --net=eth0 --netfilter firefox & | 981 | $ firejail --name=browser --net=eth0 --netfilter firefox & |
963 | .br | 982 | .br |
964 | $ firejail --netfilter6.print=browser | 983 | $ firejail --netfilter6.print=browser |
965 | 984 | ||
diff --git a/test/fnetfilter/cmdline.exp b/test/fnetfilter/cmdline.exp new file mode 100755 index 000000000..1a0b1c5aa --- /dev/null +++ b/test/fnetfilter/cmdline.exp | |||
@@ -0,0 +1,37 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2017 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "fnetfilter\r" | ||
11 | expect { | ||
12 | timeout {puts "TESTING ERROR 1\n";exit} | ||
13 | "Usage:" | ||
14 | } | ||
15 | after 100 | ||
16 | |||
17 | send -- "fnetfilter -h\r" | ||
18 | expect { | ||
19 | timeout {puts "TESTING ERROR 2\n";exit} | ||
20 | "Usage:" | ||
21 | } | ||
22 | after 100 | ||
23 | |||
24 | send -- "fnetfilter -h a b c d\r" | ||
25 | expect { | ||
26 | timeout {puts "TESTING ERROR 2\n";exit} | ||
27 | "Usage:" | ||
28 | } | ||
29 | after 100 | ||
30 | |||
31 | send -- "fnetfilter a b c d\r" | ||
32 | expect { | ||
33 | timeout {puts "TESTING ERROR 2\n";exit} | ||
34 | "Usage:" | ||
35 | } | ||
36 | after 100 | ||
37 | puts "\nall done\n" | ||
diff --git a/test/fnetfilter/copy.exp b/test/fnetfilter/copy.exp new file mode 100755 index 000000000..65145ec4b --- /dev/null +++ b/test/fnetfilter/copy.exp | |||
@@ -0,0 +1,52 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2017 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "rm outfile\r" | ||
11 | after 100 | ||
12 | |||
13 | send -- "fnetfilter test1.net outfile\r" | ||
14 | after 100 | ||
15 | |||
16 | send -- "cat outfile\r" | ||
17 | expect { | ||
18 | timeout {puts "TESTING ERROR 1\n";exit} | ||
19 | "test1" | ||
20 | } | ||
21 | expect { | ||
22 | timeout {puts "TESTING ERROR 2\n";exit} | ||
23 | "*filter" | ||
24 | } | ||
25 | expect { | ||
26 | timeout {puts "TESTING ERROR 3\n";exit} | ||
27 | "INPUT -m state --state RELATED,ESTABLISHED" | ||
28 | } | ||
29 | expect { | ||
30 | timeout {puts "TESTING ERROR 4\n";exit} | ||
31 | "disable STUN" | ||
32 | } | ||
33 | after 100 | ||
34 | |||
35 | send -- "fnetfilter foo outfile\r" | ||
36 | expect { | ||
37 | timeout {puts "TESTING ERROR 5\n";exit} | ||
38 | "cannot open foo" | ||
39 | } | ||
40 | after 100 | ||
41 | |||
42 | send -- "fnetfilter test1.net outlocked\r" | ||
43 | expect { | ||
44 | timeout {puts "TESTING ERROR 6\n";exit} | ||
45 | "cannot open outlocked" | ||
46 | } | ||
47 | after 100 | ||
48 | |||
49 | send -- "rm outfile\r" | ||
50 | after 100 | ||
51 | |||
52 | puts "\nall done\n" | ||
diff --git a/test/fnetfilter/default.exp b/test/fnetfilter/default.exp new file mode 100755 index 000000000..d7c9d91d5 --- /dev/null +++ b/test/fnetfilter/default.exp | |||
@@ -0,0 +1,40 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2017 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "rm outfile\r" | ||
11 | after 100 | ||
12 | |||
13 | send -- "fnetfilter outfile\r" | ||
14 | after 100 | ||
15 | |||
16 | send -- "cat outfile\r" | ||
17 | expect { | ||
18 | timeout {puts "TESTING ERROR 1\n";exit} | ||
19 | "*filter" | ||
20 | } | ||
21 | expect { | ||
22 | timeout {puts "TESTING ERROR 2\n";exit} | ||
23 | "INPUT -m state --state RELATED,ESTABLISHED" | ||
24 | } | ||
25 | expect { | ||
26 | timeout {puts "TESTING ERROR 3\n";exit} | ||
27 | "disable STUN" | ||
28 | } | ||
29 | after 100 | ||
30 | |||
31 | send -- "fnetfilter test1.net,33\r" | ||
32 | expect { | ||
33 | timeout {puts "TESTING ERROR 4\n";exit} | ||
34 | "invalid destination file in netfilter command" | ||
35 | } | ||
36 | after 100 | ||
37 | send -- "rm outfile\r" | ||
38 | after 100 | ||
39 | |||
40 | puts "\nall done\n" | ||
diff --git a/test/fnetfilter/fnetfilter.sh b/test/fnetfilter/fnetfilter.sh new file mode 100755 index 000000000..5fd08d186 --- /dev/null +++ b/test/fnetfilter/fnetfilter.sh | |||
@@ -0,0 +1,28 @@ | |||
1 | #!/bin/bash | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2017 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | export MALLOC_CHECK_=3 | ||
7 | export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) | ||
8 | |||
9 | if [ -f /etc/debian_version ]; then | ||
10 | libdir=$(dirname "$(dpkg -L firejail | grep fcopy)") | ||
11 | export PATH="$PATH:$libdir" | ||
12 | fi | ||
13 | |||
14 | export PATH="$PATH:/usr/lib/firejail" | ||
15 | |||
16 | echo "TESTING: fnetfilter cmdline (test/fnetfilter/cmdline.exp)" | ||
17 | ./cmdline.exp | ||
18 | |||
19 | echo "TESTING: fnetfilter default (test/fnetfilter/default.exp)" | ||
20 | ./default.exp | ||
21 | |||
22 | echo "TESTING: fnetfilter copy (test/fnetfilter/copy.exp)" | ||
23 | ./copy.exp | ||
24 | |||
25 | echo "TESTING: fnetfilter template (test/fnetfilter/template.exp)" | ||
26 | ./template.exp | ||
27 | |||
28 | rm -f outfile | ||
diff --git a/test/fnetfilter/outlocked b/test/fnetfilter/outlocked new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/fnetfilter/outlocked | |||
diff --git a/test/fnetfilter/template.exp b/test/fnetfilter/template.exp new file mode 100755 index 000000000..eb57313bd --- /dev/null +++ b/test/fnetfilter/template.exp | |||
@@ -0,0 +1,82 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2017 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "rm outfile\r" | ||
11 | after 100 | ||
12 | |||
13 | send -- "fnetfilter test2.net,icmp-type,destination-unreachable,time-exceeded,echo-request,3478,3479 outfile\r" | ||
14 | after 100 | ||
15 | |||
16 | send -- "cat outfile\r" | ||
17 | expect { | ||
18 | timeout {puts "TESTING ERROR 1\n";exit} | ||
19 | "*filter" | ||
20 | } | ||
21 | expect { | ||
22 | timeout {puts "TESTING ERROR 2\n";exit} | ||
23 | "INPUT -m state --state RELATED,ESTABLISHED" | ||
24 | } | ||
25 | expect { | ||
26 | timeout {puts "TESTING ERROR 3\n";exit} | ||
27 | "icmp-type echo-reply" | ||
28 | } | ||
29 | expect { | ||
30 | timeout {puts "TESTING ERROR 4\n";exit} | ||
31 | "icmp-type destination-unreachable" | ||
32 | } | ||
33 | expect { | ||
34 | timeout {puts "TESTING ERROR 5\n";exit} | ||
35 | "icmp-type time-exceeded" | ||
36 | } | ||
37 | expect { | ||
38 | timeout {puts "TESTING ERROR 6\n";exit} | ||
39 | "icmp-type echo-request" | ||
40 | } | ||
41 | expect { | ||
42 | timeout {puts "TESTING ERROR 7\n";exit} | ||
43 | "dport 3478" | ||
44 | } | ||
45 | expect { | ||
46 | timeout {puts "TESTING ERROR 8\n";exit} | ||
47 | "dport 3479" | ||
48 | } | ||
49 | expect { | ||
50 | timeout {puts "TESTING ERROR 8\n";exit} | ||
51 | "dport 3478" | ||
52 | } | ||
53 | expect { | ||
54 | timeout {puts "TESTING ERROR 10\n";exit} | ||
55 | "dport 3479" | ||
56 | } | ||
57 | after 100 | ||
58 | |||
59 | send -- "fnetfilter test2.net,icmp-type,destination-unreachable,time-exceeded,echo-request outfile\r" | ||
60 | expect { | ||
61 | timeout {puts "TESTING ERROR 11\n";exit} | ||
62 | "ARG5 on line 14 was not defined" | ||
63 | } | ||
64 | after 100 | ||
65 | |||
66 | send -- "fnetfilter test2.net,icmp-type,destination-unreachable,time-exceeded,echo-request\r" | ||
67 | expect { | ||
68 | timeout {puts "TESTING ERROR 12\n";exit} | ||
69 | "invalid destination file in netfilter command" | ||
70 | } | ||
71 | after 100 | ||
72 | |||
73 | send -- "fnetfilter test3.net,44 outfile\r" | ||
74 | expect { | ||
75 | timeout {puts "TESTING ERROR 13\n";exit} | ||
76 | "invalid template argument on line 1" | ||
77 | } | ||
78 | after 100 | ||
79 | send -- "rm outfile\r" | ||
80 | after 100 | ||
81 | |||
82 | puts "\nall done\n" | ||
diff --git a/test/fnetfilter/test1.net b/test/fnetfilter/test1.net new file mode 100644 index 000000000..59bef1443 --- /dev/null +++ b/test/fnetfilter/test1.net | |||
@@ -0,0 +1,19 @@ | |||
1 | *filter | ||
2 | # test2 | ||
3 | :INPUT DROP [0:0] | ||
4 | :FORWARD DROP [0:0] | ||
5 | :OUTPUT ACCEPT [0:0] | ||
6 | -A INPUT -i lo -j ACCEPT | ||
7 | -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT | ||
8 | # echo replay is handled by -m state RELATED/ESTABLISHED above | ||
9 | #-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT | ||
10 | -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT | ||
11 | -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT | ||
12 | -A INPUT -p icmp --icmp-type echo-request -j ACCEPT | ||
13 | # disable STUN | ||
14 | -A OUTPUT -p udp --dport 3478 -j DROP | ||
15 | -A OUTPUT -p udp --dport 3479 -j DROP | ||
16 | -A OUTPUT -p tcp --dport 3478 -j DROP | ||
17 | -A OUTPUT -p tcp --dport 3479 -j DROP | ||
18 | COMMIT | ||
19 | |||
diff --git a/test/fnetfilter/test2.net b/test/fnetfilter/test2.net new file mode 100644 index 000000000..a02785413 --- /dev/null +++ b/test/fnetfilter/test2.net | |||
@@ -0,0 +1,19 @@ | |||
1 | *filter | ||
2 | # test2 | ||
3 | :INPUT DROP [0:0] | ||
4 | :FORWARD DROP [0:0] | ||
5 | :OUTPUT ACCEPT [0:0] | ||
6 | -A INPUT -i lo -j ACCEPT | ||
7 | -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT | ||
8 | # echo replay is handled by -m state RELATED/ESTABLISHED above | ||
9 | #-A INPUT -p icmp --$ARG1 echo-reply -j ACCEPT | ||
10 | -A INPUT -p icmp --$ARG1 $ARG2 -j ACCEPT | ||
11 | -A INPUT -p icmp --$ARG1 $ARG3 -j ACCEPT | ||
12 | -A INPUT -p icmp --$ARG1 $ARG4 -j ACCEPT | ||
13 | # disable STUN | ||
14 | -A OUTPUT -p udp --dport $ARG5 -j DROP | ||
15 | -A OUTPUT -p udp --dport $ARG6 -j DROP | ||
16 | -A OUTPUT -p tcp --dport $ARG5 -j DROP | ||
17 | -A OUTPUT -p tcp --dport $ARG6 -j DROP | ||
18 | COMMIT | ||
19 | |||
diff --git a/test/fnetfilter/test3.net b/test/fnetfilter/test3.net new file mode 100644 index 000000000..702cb06b3 --- /dev/null +++ b/test/fnetfilter/test3.net | |||
@@ -0,0 +1 @@ | |||
asdfasdf $ARG asdfasdfdasf | |||
diff --git a/test/network/netfilter-template.exp b/test/network/netfilter-template.exp new file mode 100755 index 000000000..637b32468 --- /dev/null +++ b/test/network/netfilter-template.exp | |||
@@ -0,0 +1,44 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2017 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "firejail --net=br1 --ip=10.10.30.10 --name=test1 --netfilter=/etc/firejail/tcpserver.net,5555 ./tcpserver 5555\r" | ||
11 | expect { | ||
12 | timeout {puts "TESTING ERROR 1\n";exit} | ||
13 | "Child process initialized" | ||
14 | } | ||
15 | sleep 1 | ||
16 | |||
17 | spawn $env(SHELL) | ||
18 | send -- "telnet 10.10.30.10 5555\r" | ||
19 | expect { | ||
20 | timeout {puts "TESTING ERROR 2\n";exit} | ||
21 | "Connected to 10.10.30.10" | ||
22 | } | ||
23 | sleep 1 | ||
24 | |||
25 | send "sdfklsjadfl;ksadjfl;sdkfj\r" | ||
26 | expect { | ||
27 | timeout {puts "TESTING ERROR 3\n";exit} | ||
28 | "response" | ||
29 | } | ||
30 | expect { | ||
31 | timeout {puts "TESTING ERROR 4\n";exit} | ||
32 | "Connection closed" | ||
33 | } | ||
34 | sleep 1 | ||
35 | |||
36 | send -- "telnet 10.10.30.10 5556\r" | ||
37 | expect { | ||
38 | timeout {puts "OK\n"} | ||
39 | "Connected to 10.10.30.10" {puts "TESTING ERROR 6\n";exit} | ||
40 | "dikasdfjasdjf" | ||
41 | } | ||
42 | |||
43 | after 100 | ||
44 | puts "all done\n" | ||
diff --git a/test/network/network.sh b/test/network/network.sh index 739644c8e..83a70f1e3 100755 --- a/test/network/network.sh +++ b/test/network/network.sh | |||
@@ -8,6 +8,12 @@ export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) | |||
8 | 8 | ||
9 | sudo ./configure | 9 | sudo ./configure |
10 | 10 | ||
11 | echo "TESTING: netfilter template (netfilter-template.exp)" | ||
12 | rm -f ./tcpserver | ||
13 | gcc -o tcpserver tcpserver.c | ||
14 | ./netfilter-template.exp | ||
15 | rm ./tcpserver | ||
16 | |||
11 | echo "TESTING: firemon interface (firemon-interfaces.exp)" | 17 | echo "TESTING: firemon interface (firemon-interfaces.exp)" |
12 | sudo ./firemon-interfaces.exp | 18 | sudo ./firemon-interfaces.exp |
13 | 19 | ||
diff --git a/test/network/tcpserver.c b/test/network/tcpserver.c new file mode 100644 index 000000000..b2395a4ad --- /dev/null +++ b/test/network/tcpserver.c | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2017 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <unistd.h> | ||
23 | #include <netdb.h> | ||
24 | #include <netinet/in.h> | ||
25 | #include <string.h> | ||
26 | |||
27 | |||
28 | int main(int argc, char **argv) { | ||
29 | int fd, newfd, client_len; | ||
30 | struct sockaddr_in serv_addr, client_addr; | ||
31 | int n, pid; | ||
32 | |||
33 | if (argc < 2) { | ||
34 | printf("Usage: ./server port-number\n"); | ||
35 | return 1; | ||
36 | } | ||
37 | int portno = atoi(argv[1]); | ||
38 | |||
39 | // init socket | ||
40 | fd = socket(AF_INET, SOCK_STREAM, 0); | ||
41 | if (fd < 0) { | ||
42 | perror("ERROR opening socket"); | ||
43 | return 1; | ||
44 | } | ||
45 | |||
46 | // Initialize socket structure | ||
47 | memset(&serv_addr, 0, sizeof(serv_addr)); | ||
48 | |||
49 | serv_addr.sin_family = AF_INET; | ||
50 | serv_addr.sin_addr.s_addr = INADDR_ANY; | ||
51 | serv_addr.sin_port = htons(portno); | ||
52 | |||
53 | // bind | ||
54 | if (bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { | ||
55 | perror("bind"); | ||
56 | return 1; | ||
57 | } | ||
58 | |||
59 | // listen - 5 pending conncections | ||
60 | if (listen(fd, 5) < 0) { | ||
61 | perror("listen"); | ||
62 | return 1; | ||
63 | } | ||
64 | client_len = sizeof(client_addr); | ||
65 | |||
66 | while (1) { | ||
67 | newfd = accept(fd, (struct sockaddr *) &client_addr, &client_len); | ||
68 | |||
69 | if (newfd < 0) { | ||
70 | perror("accept"); | ||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | /* Create child process */ | ||
75 | pid = fork(); | ||
76 | |||
77 | if (pid < 0) { | ||
78 | perror("fork"); | ||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | if (pid == 0) { | ||
83 | // child | ||
84 | close(fd); | ||
85 | #define MAXBUF 4096 | ||
86 | char buf[MAXBUF]; | ||
87 | memset(buf, 0, MAXBUF); | ||
88 | |||
89 | int rcv = read(newfd, buf, MAXBUF - 1); | ||
90 | if (rcv < 0) { | ||
91 | perror("read"); | ||
92 | exit(1); | ||
93 | } | ||
94 | |||
95 | int sent = write(newfd, "response\n", 9); | ||
96 | if (sent < 9) { | ||
97 | perror("write"); | ||
98 | return 1; | ||
99 | } | ||
100 | |||
101 | exit(0); | ||
102 | } | ||
103 | else | ||
104 | close(newfd); | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||