diff options
-rw-r--r-- | src/firejail/firejail.h | 8 | ||||
-rw-r--r-- | src/firejail/fs_hostname.c | 10 | ||||
-rw-r--r-- | src/firejail/main.c | 36 | ||||
-rw-r--r-- | src/firejail/network.c | 34 | ||||
-rw-r--r-- | src/firejail/profile.c | 37 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 14 | ||||
-rwxr-xr-x | test/environment/dns.exp | 10 | ||||
-rw-r--r-- | test/environment/dns.profile | 1 | ||||
-rwxr-xr-x | test/utils/dns-print.exp | 6 |
9 files changed, 111 insertions, 45 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index a76d2795d..e96a5d63e 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -240,9 +240,10 @@ typedef struct config_t { | |||
240 | Interface interface1; | 240 | Interface interface1; |
241 | Interface interface2; | 241 | Interface interface2; |
242 | Interface interface3; | 242 | Interface interface3; |
243 | uint32_t dns1; // up to 3 IP addresses for dns servers | 243 | char *dns1; // up to 3 IP (v4/v6) addresses for dns servers |
244 | uint32_t dns2; | 244 | char *dns2; |
245 | uint32_t dns3; | 245 | char *dns3; |
246 | char *dns4; | ||
246 | 247 | ||
247 | // seccomp | 248 | // seccomp |
248 | char *seccomp_list;// optional seccomp list on top of default filter | 249 | char *seccomp_list;// optional seccomp list on top of default filter |
@@ -409,6 +410,7 @@ void net_dns_print(pid_t pid); | |||
409 | void network_main(pid_t child); | 410 | void network_main(pid_t child); |
410 | 411 | ||
411 | // network.c | 412 | // network.c |
413 | int check_ip46_address(const char *addr); | ||
412 | void net_if_up(const char *ifname); | 414 | void net_if_up(const char *ifname); |
413 | void net_if_down(const char *ifname); | 415 | void net_if_down(const char *ifname); |
414 | void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu); | 416 | void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu); |
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index 137686572..fd823b812 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c | |||
@@ -89,7 +89,7 @@ errexit: | |||
89 | } | 89 | } |
90 | 90 | ||
91 | void fs_resolvconf(void) { | 91 | void fs_resolvconf(void) { |
92 | if (cfg.dns1 == 0) | 92 | if (cfg.dns1 == NULL) |
93 | return; | 93 | return; |
94 | 94 | ||
95 | if (arg_debug) | 95 | if (arg_debug) |
@@ -164,11 +164,13 @@ void fs_resolvconf(void) { | |||
164 | } | 164 | } |
165 | 165 | ||
166 | if (cfg.dns1) | 166 | if (cfg.dns1) |
167 | fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns1)); | 167 | fprintf(fp, "nameserver %s\n", cfg.dns1); |
168 | if (cfg.dns2) | 168 | if (cfg.dns2) |
169 | fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns2)); | 169 | fprintf(fp, "nameserver %s\n", cfg.dns2); |
170 | if (cfg.dns3) | 170 | if (cfg.dns3) |
171 | fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns3)); | 171 | fprintf(fp, "nameserver %s\n", cfg.dns3); |
172 | if (cfg.dns4) | ||
173 | fprintf(fp, "nameserver %s\n", cfg.dns4); | ||
172 | 174 | ||
173 | // mode and owner | 175 | // mode and owner |
174 | SET_PERMS_STREAM(fp, 0, 0, 0644); | 176 | SET_PERMS_STREAM(fp, 0, 0, 0644); |
diff --git a/src/firejail/main.c b/src/firejail/main.c index bc6eb8219..9cd89d42c 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -2034,18 +2034,20 @@ int main(int argc, char **argv) { | |||
2034 | fprintf(stderr, "Error: no network device configured\n"); | 2034 | fprintf(stderr, "Error: no network device configured\n"); |
2035 | exit(1); | 2035 | exit(1); |
2036 | } | 2036 | } |
2037 | if (br->arg_ip_none || br->ip6sandbox) { | 2037 | if (br->ip6sandbox) { |
2038 | fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); | 2038 | fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); |
2039 | exit(1); | 2039 | exit(1); |
2040 | } | 2040 | } |
2041 | 2041 | ||
2042 | // configure this IP address for the last bridge defined | 2042 | // configure this IP address for the last bridge defined |
2043 | // todo: verify ipv6 syntax | 2043 | if (check_ip46_address(argv[i] + 6) == 0) { |
2044 | br->ip6sandbox = argv[i] + 6; | 2044 | fprintf(stderr, "Error: invalid IPv6 address\n"); |
2045 | // if (atoip(argv[i] + 5, &br->ipsandbox)) { | 2045 | exit(1); |
2046 | // fprintf(stderr, "Error: invalid IP address\n"); | 2046 | } |
2047 | // exit(1); | 2047 | |
2048 | // } | 2048 | br->ip6sandbox = strdup(argv[i] + 6); |
2049 | if (br->ip6sandbox == NULL) | ||
2050 | errExit("strdup"); | ||
2049 | } | 2051 | } |
2050 | else | 2052 | else |
2051 | exit_err_feature("networking"); | 2053 | exit_err_feature("networking"); |
@@ -2064,20 +2066,24 @@ int main(int argc, char **argv) { | |||
2064 | } | 2066 | } |
2065 | #endif | 2067 | #endif |
2066 | else if (strncmp(argv[i], "--dns=", 6) == 0) { | 2068 | else if (strncmp(argv[i], "--dns=", 6) == 0) { |
2067 | uint32_t dns; | 2069 | if (check_ip46_address(argv[i] + 6) == 0) { |
2068 | if (atoip(argv[i] + 6, &dns)) { | 2070 | fprintf(stderr, "Error: invalid DNS server IPv4 or IPv6 address\n"); |
2069 | fprintf(stderr, "Error: invalid DNS server IP address\n"); | 2071 | exit(1); |
2070 | return 1; | ||
2071 | } | 2072 | } |
2073 | char *dns = strdup(argv[i] + 6); | ||
2074 | if (!dns) | ||
2075 | errExit("strdup"); | ||
2072 | 2076 | ||
2073 | if (cfg.dns1 == 0) | 2077 | if (cfg.dns1 == NULL) |
2074 | cfg.dns1 = dns; | 2078 | cfg.dns1 = dns; |
2075 | else if (cfg.dns2 == 0) | 2079 | else if (cfg.dns2 == NULL) |
2076 | cfg.dns2 = dns; | 2080 | cfg.dns2 = dns; |
2077 | else if (cfg.dns3 == 0) | 2081 | else if (cfg.dns3 == NULL) |
2078 | cfg.dns3 = dns; | 2082 | cfg.dns3 = dns; |
2083 | else if (cfg.dns4 == NULL) | ||
2084 | cfg.dns4 = dns; | ||
2079 | else { | 2085 | else { |
2080 | fprintf(stderr, "Error: up to 3 DNS servers can be specified\n"); | 2086 | fprintf(stderr, "Error: up to 4 DNS servers can be specified\n"); |
2081 | return 1; | 2087 | return 1; |
2082 | } | 2088 | } |
2083 | } | 2089 | } |
diff --git a/src/firejail/network.c b/src/firejail/network.c index 80f150ea0..7b84854d3 100644 --- a/src/firejail/network.c +++ b/src/firejail/network.c | |||
@@ -28,6 +28,40 @@ | |||
28 | #include <net/route.h> | 28 | #include <net/route.h> |
29 | #include <linux/if_bridge.h> | 29 | #include <linux/if_bridge.h> |
30 | 30 | ||
31 | // return 1 if addr is a IPv4 or IPv6 address | ||
32 | int check_ip46_address(const char *addr) { | ||
33 | // check ipv4 address | ||
34 | uint32_t tmp; | ||
35 | if (atoip(addr, &tmp) == 0) | ||
36 | return 1; | ||
37 | |||
38 | // check ipv6 address | ||
39 | struct in6_addr result; | ||
40 | |||
41 | char *tmpstr = strdup(addr); | ||
42 | if (!tmpstr) | ||
43 | errExit("strdup"); | ||
44 | char *ptr = strchr(tmpstr, '/'); | ||
45 | if (ptr) { | ||
46 | *ptr = '\0'; | ||
47 | ptr++; | ||
48 | int mask = atoi(ptr); | ||
49 | // check the network mask | ||
50 | if (mask < 0 || mask > 128) { | ||
51 | free(tmpstr); | ||
52 | return 0; | ||
53 | } | ||
54 | } | ||
55 | if (inet_pton(AF_INET6, tmpstr, &result) == 1) { | ||
56 | free(tmpstr); | ||
57 | return 1; | ||
58 | } | ||
59 | |||
60 | free(tmpstr); | ||
61 | |||
62 | // failed | ||
63 | return 0; | ||
64 | } | ||
31 | 65 | ||
32 | int net_get_mtu(const char *ifname) { | 66 | int net_get_mtu(const char *ifname) { |
33 | int mtu = 0; | 67 | int mtu = 0; |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 1a944beff..d0c43d13e 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -502,18 +502,20 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
502 | fprintf(stderr, "Error: no network device configured\n"); | 502 | fprintf(stderr, "Error: no network device configured\n"); |
503 | exit(1); | 503 | exit(1); |
504 | } | 504 | } |
505 | if (br->arg_ip_none || br->ip6sandbox) { | 505 | if (br->ip6sandbox) { |
506 | fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); | 506 | fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); |
507 | exit(1); | 507 | exit(1); |
508 | } | 508 | } |
509 | 509 | ||
510 | // configure this IP address for the last bridge defined | 510 | // configure this IP address for the last bridge defined |
511 | // todo: verify ipv6 syntax | 511 | if (check_ip46_address(ptr + 4) == 0) { |
512 | br->ip6sandbox = ptr + 4; | 512 | fprintf(stderr, "Error: invalid IPv6 address\n"); |
513 | // if (atoip(argv[i] + 5, &br->ipsandbox)) { | 513 | exit(1); |
514 | // fprintf(stderr, "Error: invalid IP address\n"); | 514 | } |
515 | // exit(1); | 515 | |
516 | // } | 516 | br->ip6sandbox = strdup(ptr + 4); |
517 | if (br->ip6sandbox == NULL) | ||
518 | errExit("strdup"); | ||
517 | 519 | ||
518 | } | 520 | } |
519 | else | 521 | else |
@@ -668,20 +670,25 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
668 | 670 | ||
669 | // dns | 671 | // dns |
670 | if (strncmp(ptr, "dns ", 4) == 0) { | 672 | if (strncmp(ptr, "dns ", 4) == 0) { |
671 | uint32_t dns; | 673 | |
672 | if (atoip(ptr + 4, &dns)) { | 674 | if (check_ip46_address(ptr + 4) == 0) { |
673 | fprintf(stderr, "Error: invalid DNS server IP address\n"); | 675 | fprintf(stderr, "Error: invalid DNS server IPv4 or IPv6 address\n"); |
674 | return 1; | 676 | exit(1); |
675 | } | 677 | } |
678 | char *dns = strdup(ptr + 4); | ||
679 | if (!dns) | ||
680 | errExit("strdup"); | ||
676 | 681 | ||
677 | if (cfg.dns1 == 0) | 682 | if (cfg.dns1 == NULL) |
678 | cfg.dns1 = dns; | 683 | cfg.dns1 = dns; |
679 | else if (cfg.dns2 == 0) | 684 | else if (cfg.dns2 == NULL) |
680 | cfg.dns2 = dns; | 685 | cfg.dns2 = dns; |
681 | else if (cfg.dns3 == 0) | 686 | else if (cfg.dns3 == NULL) |
682 | cfg.dns3 = dns; | 687 | cfg.dns3 = dns; |
688 | else if (cfg.dns4 == NULL) | ||
689 | cfg.dns4 = dns; | ||
683 | else { | 690 | else { |
684 | fprintf(stderr, "Error: up to 3 DNS servers can be specified\n"); | 691 | fprintf(stderr, "Error: up to 4 DNS servers can be specified\n"); |
685 | return 1; | 692 | return 1; |
686 | } | 693 | } |
687 | return 0; | 694 | return 0; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 010bb06e0..ed0a253b3 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -652,12 +652,14 @@ int sandbox(void* sandbox_arg) { | |||
652 | else | 652 | else |
653 | fmessage("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw)); | 653 | fmessage("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw)); |
654 | } | 654 | } |
655 | if (cfg.dns1 != 0) | 655 | if (cfg.dns1 != NULL) |
656 | fmessage("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1)); | 656 | fmessage("DNS server %s\n", cfg.dns1); |
657 | if (cfg.dns2 != 0) | 657 | if (cfg.dns2 != NULL) |
658 | fmessage("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2)); | 658 | fmessage("DNS server %s\n", cfg.dns2); |
659 | if (cfg.dns3 != 0) | 659 | if (cfg.dns3 != NULL) |
660 | fmessage("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3)); | 660 | fmessage("DNS server %s\n", cfg.dns3); |
661 | if (cfg.dns4 != NULL) | ||
662 | fmessage("DNS server %s\n", cfg.dns4); | ||
661 | fmessage("\n"); | 663 | fmessage("\n"); |
662 | } | 664 | } |
663 | } | 665 | } |
diff --git a/test/environment/dns.exp b/test/environment/dns.exp index 0d12a82f2..6ddc0ccea 100755 --- a/test/environment/dns.exp +++ b/test/environment/dns.exp | |||
@@ -4,7 +4,7 @@ set timeout 30 | |||
4 | spawn $env(SHELL) | 4 | spawn $env(SHELL) |
5 | match_max 100000 | 5 | match_max 100000 |
6 | 6 | ||
7 | send -- "firejail --dns=8.8.4.4 --dns=8.8.8.8 --dns=4.2.2.1\r" | 7 | send -- "firejail --dns=8.8.4.4 --dns=8.8.8.8 --dns=4.2.2.1 --dns=::2\r" |
8 | expect { | 8 | expect { |
9 | timeout {puts "TESTING ERROR 2.1\n";exit} | 9 | timeout {puts "TESTING ERROR 2.1\n";exit} |
10 | "Child process initialized" | 10 | "Child process initialized" |
@@ -24,6 +24,10 @@ expect { | |||
24 | timeout {puts "TESTING ERROR 2.4\n";exit} | 24 | timeout {puts "TESTING ERROR 2.4\n";exit} |
25 | "nameserver 4.2.2.1" | 25 | "nameserver 4.2.2.1" |
26 | } | 26 | } |
27 | expect { | ||
28 | timeout {puts "TESTING ERROR 2.5\n";exit} | ||
29 | "nameserver ::2" | ||
30 | } | ||
27 | after 100 | 31 | after 100 |
28 | send -- "exit\r" | 32 | send -- "exit\r" |
29 | sleep 1 | 33 | sleep 1 |
@@ -50,6 +54,10 @@ expect { | |||
50 | "nameserver 4.2.2.1" | 54 | "nameserver 4.2.2.1" |
51 | } | 55 | } |
52 | after 100 | 56 | after 100 |
57 | expect { | ||
58 | timeout {puts "TESTING ERROR 12.5\n";exit} | ||
59 | "nameserver ::2" | ||
60 | } | ||
53 | send -- "exit\r" | 61 | send -- "exit\r" |
54 | sleep 1 | 62 | sleep 1 |
55 | 63 | ||
diff --git a/test/environment/dns.profile b/test/environment/dns.profile index d1b842c86..ade2f2650 100644 --- a/test/environment/dns.profile +++ b/test/environment/dns.profile | |||
@@ -1,3 +1,4 @@ | |||
1 | dns 8.8.4.4 | 1 | dns 8.8.4.4 |
2 | dns 8.8.8.8 | 2 | dns 8.8.8.8 |
3 | dns 4.2.2.1 | 3 | dns 4.2.2.1 |
4 | dns ::2 | ||
diff --git a/test/utils/dns-print.exp b/test/utils/dns-print.exp index 1954844c9..a0fbaa12f 100755 --- a/test/utils/dns-print.exp +++ b/test/utils/dns-print.exp | |||
@@ -7,7 +7,7 @@ set timeout 10 | |||
7 | spawn $env(SHELL) | 7 | spawn $env(SHELL) |
8 | match_max 100000 | 8 | match_max 100000 |
9 | 9 | ||
10 | send -- "firejail --name=test --dns=1.2.3.4\r" | 10 | send -- "firejail --name=test --dns=1.2.3.4 --dns=::2\r" |
11 | expect { | 11 | expect { |
12 | timeout {puts "TESTING ERROR 0\n";exit} | 12 | timeout {puts "TESTING ERROR 0\n";exit} |
13 | "Child process initialized" | 13 | "Child process initialized" |
@@ -20,5 +20,9 @@ expect { | |||
20 | timeout {puts "TESTING ERROR 1\n";exit} | 20 | timeout {puts "TESTING ERROR 1\n";exit} |
21 | "nameserver 1.2.3.4" | 21 | "nameserver 1.2.3.4" |
22 | } | 22 | } |
23 | expect { | ||
24 | timeout {puts "TESTING ERROR 1\n";exit} | ||
25 | "nameserver ::2" | ||
26 | } | ||
23 | after 100 | 27 | after 100 |
24 | puts "\nall done\n" | 28 | puts "\nall done\n" |