diff options
author | 2017-07-29 07:38:20 -0400 | |
---|---|---|
committer | 2017-07-29 07:38:20 -0400 | |
commit | b1595955089ae80755b8af4d2b1457712b95926a (patch) | |
tree | 59e800e35b5bd99b50c0b6526edb969c853557a2 | |
parent | network testing (diff) | |
download | firejail-b1595955089ae80755b8af4d2b1457712b95926a.tar.gz firejail-b1595955089ae80755b8af4d2b1457712b95926a.tar.zst firejail-b1595955089ae80755b8af4d2b1457712b95926a.zip |
arp rework
-rw-r--r-- | RELNOTES | 1 | ||||
-rw-r--r-- | etc/firejail.config | 8 | ||||
-rw-r--r-- | src/firejail/arp.c | 100 | ||||
-rw-r--r-- | src/firejail/checkcfg.c | 10 | ||||
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 2 |
6 files changed, 114 insertions, 10 deletions
@@ -4,6 +4,7 @@ firejail (0.9.49) baseline; urgency=low | |||
4 | * feature: per-profile support to set X11 Xephyr screen size (--xephyr-screen) | 4 | * feature: per-profile support to set X11 Xephyr screen size (--xephyr-screen) |
5 | * enhancement: /proc/sys mounting | 5 | * enhancement: /proc/sys mounting |
6 | * enhancement: default seccomp list update | 6 | * enhancement: default seccomp list update |
7 | * enhancement: rework IP address assingment for --net options | ||
7 | * new profiles: curl, mplayer2, SMPlayer, Calibre, ebook-viewer, KWrite, | 8 | * new profiles: curl, mplayer2, SMPlayer, Calibre, ebook-viewer, KWrite, |
8 | * new profiles: Geary, Liferea, peek, silentarmy, IntelliJ IDEA, | 9 | * new profiles: Geary, Liferea, peek, silentarmy, IntelliJ IDEA, |
9 | * new profiles: Android Studio, electron, riot-web | 10 | * new profiles: Android Studio, electron, riot-web |
diff --git a/etc/firejail.config b/etc/firejail.config index 1db33edda..22ce77324 100644 --- a/etc/firejail.config +++ b/etc/firejail.config | |||
@@ -2,6 +2,14 @@ | |||
2 | # keyword-argument pairs, one per line. Most features are enabled by default. | 2 | # keyword-argument pairs, one per line. Most features are enabled by default. |
3 | # Use 'yes' or 'no' as configuration values. | 3 | # Use 'yes' or 'no' as configuration values. |
4 | 4 | ||
5 | |||
6 | # Number of ARP probes sent when assigning an IP address for --net option, | ||
7 | # default 2. This is a partial implementation of RFC 5227. A 0.5 seconds | ||
8 | # timeout is implemented for each probe. Increase this number to 4 if your | ||
9 | # local layer 2 network uses RSTP (IEEE 802.1w). Permitted values are | ||
10 | # between 1 and 30. | ||
11 | # arp-probes 2 | ||
12 | |||
5 | # Enable or disable bind support, default enabled. | 13 | # Enable or disable bind support, default enabled. |
6 | # bind yes | 14 | # bind yes |
7 | 15 | ||
diff --git a/src/firejail/arp.c b/src/firejail/arp.c index 6d21167f0..ffbc56841 100644 --- a/src/firejail/arp.c +++ b/src/firejail/arp.c | |||
@@ -41,6 +41,79 @@ typedef struct arp_hdr_t { | |||
41 | } ArpHdr; | 41 | } ArpHdr; |
42 | 42 | ||
43 | 43 | ||
44 | // gracious arp announcing our address | ||
45 | void arp_announce(const char *dev, Bridge *br) { | ||
46 | // RFC 5227 - using a source and destination IP address of the interface | ||
47 | uint32_t srcaddr = br->ipsandbox; | ||
48 | uint32_t destaddr = br->ipsandbox; | ||
49 | |||
50 | if (strlen(dev) > IFNAMSIZ) { | ||
51 | fprintf(stderr, "Error: invalid network device name %s\n", dev); | ||
52 | exit(1); | ||
53 | } | ||
54 | |||
55 | if (arg_debug) | ||
56 | printf("Announce %d.%d.%d.%d ...\n", PRINT_IP(destaddr)); | ||
57 | |||
58 | // find interface address | ||
59 | int sock; | ||
60 | if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) | ||
61 | errExit("socket"); | ||
62 | |||
63 | srcaddr = htonl(srcaddr); | ||
64 | destaddr = htonl(destaddr); | ||
65 | |||
66 | // Find interface MAC address | ||
67 | struct ifreq ifr; | ||
68 | memset(&ifr, 0, sizeof (ifr)); | ||
69 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); | ||
70 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) | ||
71 | errExit("ioctl"); | ||
72 | close(sock); | ||
73 | |||
74 | // configure layer2 socket address information | ||
75 | struct sockaddr_ll addr; | ||
76 | memset(&addr, 0, sizeof(addr)); | ||
77 | if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) | ||
78 | errExit("if_nametoindex"); | ||
79 | addr.sll_family = AF_PACKET; | ||
80 | memcpy (addr.sll_addr, ifr.ifr_hwaddr.sa_data, 6); | ||
81 | addr.sll_halen = htons(6); | ||
82 | |||
83 | // build the arp packet header | ||
84 | ArpHdr hdr; | ||
85 | memset(&hdr, 0, sizeof(hdr)); | ||
86 | hdr.htype = htons(1); | ||
87 | hdr.ptype = htons(ETH_P_IP); | ||
88 | hdr.hlen = 6; | ||
89 | hdr.plen = 4; | ||
90 | hdr.opcode = htons(1); //ARPOP_REQUEST | ||
91 | memcpy(hdr.sender_mac, ifr.ifr_hwaddr.sa_data, 6); | ||
92 | memcpy(hdr.sender_ip, (uint8_t *)&srcaddr, 4); | ||
93 | memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4); | ||
94 | |||
95 | // build ethernet frame | ||
96 | uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc | ||
97 | memset(frame, 0, sizeof(frame)); | ||
98 | frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; | ||
99 | memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6); | ||
100 | frame[12] = ETH_P_ARP / 256; | ||
101 | frame[13] = ETH_P_ARP % 256; | ||
102 | memcpy (frame + 14, &hdr, sizeof(hdr)); | ||
103 | |||
104 | // open layer2 socket | ||
105 | if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) | ||
106 | errExit("socket"); | ||
107 | |||
108 | int len; | ||
109 | if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) | ||
110 | errExit("send"); | ||
111 | fflush(0); | ||
112 | close(sock); | ||
113 | } | ||
114 | |||
115 | |||
116 | |||
44 | // returns 0 if the address is not in use, -1 otherwise | 117 | // returns 0 if the address is not in use, -1 otherwise |
45 | int arp_check(const char *dev, uint32_t destaddr) { | 118 | int arp_check(const char *dev, uint32_t destaddr) { |
46 | // RFC 5227 - using a source IP address of 0 for probing | 119 | // RFC 5227 - using a source IP address of 0 for probing |
@@ -92,7 +165,7 @@ int arp_check(const char *dev, uint32_t destaddr) { | |||
92 | memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4); | 165 | memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4); |
93 | 166 | ||
94 | // build ethernet frame | 167 | // build ethernet frame |
95 | uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc | 168 | uint8_t frame[ETH_FRAME_LEN]; // includes eth header, vlan, and crc |
96 | memset(frame, 0, sizeof(frame)); | 169 | memset(frame, 0, sizeof(frame)); |
97 | frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; | 170 | frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; |
98 | memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6); | 171 | memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6); |
@@ -109,25 +182,34 @@ int arp_check(const char *dev, uint32_t destaddr) { | |||
109 | errExit("send"); | 182 | errExit("send"); |
110 | fflush(0); | 183 | fflush(0); |
111 | 184 | ||
112 | // wait not more than one second for an answer | 185 | // send two probes at 0.5 seconds interva; |
186 | int cnt = checkcfg(CFG_ARP_PROBES); | ||
187 | uint8_t framerx[ETH_FRAME_LEN]; // includes eth header, vlan, and crc | ||
113 | fd_set fds; | 188 | fd_set fds; |
114 | FD_ZERO(&fds); | 189 | FD_ZERO(&fds); |
115 | FD_SET(sock, &fds); | 190 | FD_SET(sock, &fds); |
116 | int maxfd = sock; | 191 | int maxfd = sock; |
117 | struct timeval ts; | 192 | struct timeval ts; |
118 | ts.tv_sec = 1; // 1 second wait time | 193 | ts.tv_sec = 0; // 0.5 seconds wait time |
119 | ts.tv_usec = 0; | 194 | ts.tv_usec = 500000; |
120 | while (1) { | 195 | while (1) { |
121 | int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts); | 196 | int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts); |
122 | if (nready < 0) | 197 | if (nready < 0) |
123 | errExit("select"); | 198 | errExit("select"); |
124 | else if (nready == 0) { // timeout | 199 | else if (nready == 0) { // timeout |
125 | close(sock); | 200 | if (--cnt <= 0) { |
126 | return 0; | 201 | close(sock); |
202 | return 0; | ||
203 | } | ||
204 | if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) | ||
205 | errExit("send"); | ||
206 | ts.tv_sec = 0; // 0.5 seconds wait time | ||
207 | ts.tv_usec = 500000; | ||
208 | fflush(0); | ||
127 | } | 209 | } |
128 | else { | 210 | else { |
129 | // read the incoming packet | 211 | // read the incoming packet |
130 | int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); | 212 | int len = recvfrom(sock, framerx, ETH_FRAME_LEN, 0, NULL, NULL); |
131 | if (len < 0) { | 213 | if (len < 0) { |
132 | perror("recvfrom"); | 214 | perror("recvfrom"); |
133 | close(sock); | 215 | close(sock); |
@@ -137,9 +219,9 @@ int arp_check(const char *dev, uint32_t destaddr) { | |||
137 | // parse the incoming packet | 219 | // parse the incoming packet |
138 | if ((unsigned int) len < 14 + sizeof(ArpHdr)) | 220 | if ((unsigned int) len < 14 + sizeof(ArpHdr)) |
139 | continue; | 221 | continue; |
140 | if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) | 222 | if (framerx[12] != (ETH_P_ARP / 256) || framerx[13] != (ETH_P_ARP % 256)) |
141 | continue; | 223 | continue; |
142 | memcpy(&hdr, frame + 14, sizeof(ArpHdr)); | 224 | memcpy(&hdr, framerx + 14, sizeof(ArpHdr)); |
143 | if (hdr.opcode == htons(1)) | 225 | if (hdr.opcode == htons(1)) |
144 | continue; | 226 | continue; |
145 | if (hdr.opcode == htons(2)) { | 227 | if (hdr.opcode == htons(2)) { |
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index f4e28f084..9703c9a5b 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -49,6 +49,7 @@ int checkcfg(int val) { | |||
49 | cfg_val[CFG_FIREJAIL_PROMPT] = 0; | 49 | cfg_val[CFG_FIREJAIL_PROMPT] = 0; |
50 | cfg_val[CFG_FOLLOW_SYMLINK_PRIVATE_BIN] = 0; | 50 | cfg_val[CFG_FOLLOW_SYMLINK_PRIVATE_BIN] = 0; |
51 | cfg_val[CFG_DISABLE_MNT] = 0; | 51 | cfg_val[CFG_DISABLE_MNT] = 0; |
52 | cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES; | ||
52 | 53 | ||
53 | // open configuration file | 54 | // open configuration file |
54 | const char *fname = SYSCONFDIR "/firejail.config"; | 55 | const char *fname = SYSCONFDIR "/firejail.config"; |
@@ -267,7 +268,7 @@ int checkcfg(int val) { | |||
267 | } | 268 | } |
268 | 269 | ||
269 | // Xvfb screen size | 270 | // Xvfb screen size |
270 | else if (strncmp(ptr, "xvfb-screen ", 12) == 0) { | 271 | else if (strncmp(ptr, "xvfb-screen ", 12) == 0) { |
271 | // expecting three numbers separated by x's | 272 | // expecting three numbers separated by x's |
272 | unsigned int n1; | 273 | unsigned int n1; |
273 | unsigned int n2; | 274 | unsigned int n2; |
@@ -346,6 +347,13 @@ int checkcfg(int val) { | |||
346 | else | 347 | else |
347 | goto errout; | 348 | goto errout; |
348 | } | 349 | } |
350 | // arp probes | ||
351 | else if (strncmp(ptr, "arp-probes ", 11) == 0) { | ||
352 | int arp_probes = atoi(ptr + 11); | ||
353 | if (arp_probes <= 1 || arp_probes > 30) | ||
354 | goto errout; | ||
355 | cfg_val[CFG_ARP_PROBES] = arp_probes; | ||
356 | } | ||
349 | else | 357 | else |
350 | goto errout; | 358 | goto errout; |
351 | 359 | ||
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 5fd978f51..b90c8d8ed 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -446,6 +446,7 @@ void shut(pid_t pid); | |||
446 | int restricted_shell(const char *user); | 446 | int restricted_shell(const char *user); |
447 | 447 | ||
448 | // arp.c | 448 | // arp.c |
449 | void arp_announce(const char *dev, Bridge *br); | ||
449 | // returns 0 if the address is not in use, -1 otherwise | 450 | // returns 0 if the address is not in use, -1 otherwise |
450 | int arp_check(const char *dev, uint32_t destaddr); | 451 | int arp_check(const char *dev, uint32_t destaddr); |
451 | // assign an IP address using arp scanning | 452 | // assign an IP address using arp scanning |
@@ -672,6 +673,7 @@ enum { | |||
672 | void sandboxfs(int op, pid_t pid, const char *path1, const char *path2); | 673 | void sandboxfs(int op, pid_t pid, const char *path1, const char *path2); |
673 | 674 | ||
674 | // checkcfg.c | 675 | // checkcfg.c |
676 | #define DEFAULT_ARP_PROBES 2 | ||
675 | enum { | 677 | enum { |
676 | CFG_FILE_TRANSFER = 0, | 678 | CFG_FILE_TRANSFER = 0, |
677 | CFG_X11, | 679 | CFG_X11, |
@@ -694,6 +696,7 @@ enum { | |||
694 | CFG_FOLLOW_SYMLINK_PRIVATE_BIN, | 696 | CFG_FOLLOW_SYMLINK_PRIVATE_BIN, |
695 | CFG_DISABLE_MNT, | 697 | CFG_DISABLE_MNT, |
696 | CFG_JOIN, | 698 | CFG_JOIN, |
699 | CFG_ARP_PROBES, | ||
697 | CFG_MAX // this should always be the last entry | 700 | CFG_MAX // this should always be the last entry |
698 | }; | 701 | }; |
699 | extern char *xephyr_screen; | 702 | extern char *xephyr_screen; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 8c5c02d41..47c6b7a06 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -141,6 +141,7 @@ static void sandbox_if_up(Bridge *br) { | |||
141 | if (arg_debug) | 141 | if (arg_debug) |
142 | printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); | 142 | printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); |
143 | net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); | 143 | net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); |
144 | arp_announce(dev, br); | ||
144 | } | 145 | } |
145 | else if (br->arg_ip_none == 0 && br->macvlan == 1) { | 146 | else if (br->arg_ip_none == 0 && br->macvlan == 1) { |
146 | // reassign the macvlan address | 147 | // reassign the macvlan address |
@@ -163,6 +164,7 @@ static void sandbox_if_up(Bridge *br) { | |||
163 | if (arg_debug) | 164 | if (arg_debug) |
164 | printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); | 165 | printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); |
165 | net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); | 166 | net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); |
167 | arp_announce(dev, br); | ||
166 | } | 168 | } |
167 | 169 | ||
168 | if (br->ip6sandbox) | 170 | if (br->ip6sandbox) |