Open brianvanderburg2 opened 11 months ago
I don't think so. In your log file the network is already established and enters the jail. In mine, it fails at assigning an IP address and does not even enter the sandbox.
Looking through the code and packet dump it makes sense.
My system sends: sender mac: 02:ba:15:00:00:10 sender ip: 0.0.0.0 target mac: 00:00:00:00:00:00 target ip: 192.168.1.30
This other system on the network send a reply: sender mac: f0:d4:15:45:5d:5d sender ip: 192.168.1.122 target mac: 02:ba:15:00:00:10 target ip: 0.0.0.0
The code is checking if the target values of the reply are the same as the sender of the probe, which they are, so returns -1, and arp_random/arp_sequential then test the result, which is not 0, so returns 0 for the "ip" which then causes arp_assign to fail.
This seems to confirm it should compare the received frame's sender IP with the probe frame's target IP, and if the same, treat as duplicate. In the code, it compares the received frame's target IP (hdr.target_ip) with the probe frame's sender IP (srcaddr) Here I don't think the MAC even matters, another ARP being received with the same sender IP that we are trying to use would mean a duplicate
It also recommends if receiving an ARP request during probing with a target ip matching the IP we are trying to use and a source mac not equal to ours, to treat as duplicate as another station may be probing to use the IP at the same time as we are
I don't have build tools on my system right now, but I'm thinking this is what the function should look like
int arp_check(const char *dev, uint32_t destaddr) {
// RFC 5227 - using a source IP address of 0 for probing
uint32_t srcaddr = 0;
if (strlen(dev) > IFNAMSIZ) {
fprintf(stderr, "Error: invalid network device name %s\n", dev);
exit(1);
}
if (arg_debug)
printf("Trying %d.%d.%d.%d ...\n", PRINT_IP(destaddr));
// find interface address
int sock;
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
errExit("socket");
srcaddr = htonl(srcaddr);
destaddr = htonl(destaddr);
// Find interface MAC address
struct ifreq ifr;
memset(&ifr, 0, sizeof (ifr));
strncpy(ifr.ifr_name, dev, IFNAMSIZ - 1);
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
errExit("ioctl");
close(sock);
// configure layer2 socket address information
struct sockaddr_ll addr;
memset(&addr, 0, sizeof(addr));
if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
errExit("if_nametoindex");
addr.sll_family = AF_PACKET;
memcpy (addr.sll_addr, ifr.ifr_hwaddr.sa_data, 6);
addr.sll_halen = ETH_ALEN;
// build the arp packet header
ArpHdr hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.htype = htons(1);
hdr.ptype = htons(ETH_P_IP);
hdr.hlen = 6;
hdr.plen = 4;
hdr.opcode = htons(1); //ARPOP_REQUEST
memcpy(hdr.sender_mac, ifr.ifr_hwaddr.sa_data, 6);
memcpy(hdr.sender_ip, (uint8_t *)&srcaddr, 4);
memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4);
// build ethernet frame
uint8_t frame[ETH_FRAME_LEN]; // includes eth header, vlan, and crc
memset(frame, 0, sizeof(frame));
frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6);
frame[12] = ETH_P_ARP / 256;
frame[13] = ETH_P_ARP % 256;
memcpy (frame + 14, &hdr, sizeof(hdr));
// open layer2 socket
if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
errExit("socket");
if (sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr)) <= 0)
errExit("send");
fflush(0);
// send two probes at 0.5 seconds interva;
int cnt = checkcfg(CFG_ARP_PROBES);
uint8_t framerx[ETH_FRAME_LEN]; // includes eth header, vlan, and crc
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
int maxfd = sock;
struct timeval ts;
gettimeofday(&ts, NULL);
double timerend = ts.tv_sec + ts.tv_usec / 1000000.0 + 0.5;
while (1) {
gettimeofday(&ts, NULL);
double now = ts.tv_sec + ts.tv_usec / 1000000.0;
double timeout = timerend - now;
ts.tv_sec = timeout;
ts.tv_usec = (timeout - ts.tv_sec) * 1000000;
int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts);
if (nready < 0)
errExit("select");
else if (nready == 0) { // timeout
if (--cnt <= 0) {
close(sock);
return 0;
}
if (sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr)) <= 0)
errExit("send");
gettimeofday(&ts, NULL);
timerend = ts.tv_sec + ts.tv_usec / 1000000.0 + 0.5;
fflush(0);
}
else {
// read the incoming packet
int len = recvfrom(sock, framerx, ETH_FRAME_LEN, 0, NULL, NULL);
if (len < 0) {
perror("recvfrom");
close(sock);
return -1;
}
// parse the incoming packet
if ((unsigned int) len < 14 + sizeof(ArpHdr))
continue;
if (framerx[12] != (ETH_P_ARP / 256) || framerx[13] != (ETH_P_ARP % 256))
continue;
memcpy(&hdr, framerx + 14, sizeof(ArpHdr));
if (hdr.opcode == htons(1))
continue;
if (hdr.opcode == htons(2)) {
// check my mac and my address
// Does this even matter at this part?
//if (memcmp(ifr.ifr_hwaddr.sa_data, hdr.target_mac, 6) != 0)
// continue;
// Here, I think we should be testing the sender IP of the received ARP reply with the dstaddr
// we were originally probing for. If equal, then another host send a reply claiming to the be
// the IP address we want to use
uint32_t ip;
//memcpy(&ip, hdr.target_ip, 4);
memcpy(&ip, hdr.sender_ip, 4);
//if (ip != srcaddr) {
if (ip != dstaddr) {
continue;
}
close(sock);
return -1;
}
}
}
__builtin_unreachable();
}
Description
Setup: A bridge is configured with a VLAN subinterface from the main interface bound to it. T When using firejail, the bridge is used as the interface with an IP range to choose from.
enp9s0 (main interface) bm-home (vlan subinterface for home/internet traffic) bhome (bridge, bm-home is placed into this bridge.) no IPs are assigned to the bridges or VLAN/main interfaces
Firejail is launched to create a veth pair to put into bhome, then processes launched under the firejail proccess have an IP/are able to access the internet. The bridge is used to allow other processes/virtual machines/macvlans/etc to also be able to access the internet when desired. This has worked perfectly fine until recently.
Profile:
Recently, I get an error indicating all the IPs are in use. I checked the wireshark capture and i notice:
Send arp probe I get a gratuitous arp from a different address on the network Send arp probe for next ip same Send arp probe for next ip same
When I don't get the gratuitous arp response, then it assignes that IP address Only one device in our network has that response so I asked them to turn it off, and when they do, it works with no problems.
Steps to Reproduce
Unsure. It seems specific to this situation
Expected behavior
After getting no ARP responses matching the IPs of the ARP probe, it should use the IP for the jail
Actual behavior
It performs an ARP probe of two random IPs, then the entire specified range, and fails with the error "Error: cannot assign an IP address; it looks like all of them are in use."
Behavior without a profile
This works, however doesn't use a new network namespace with veth interface connected to the bridge and assigned an iP, so doesn't affect/reflect on this issue
Additional context
Environment
Debian Bullesye Firejail 0.9.72
Checklist
/usr/bin/vlc
) "fixes" it).https://github.com/netblue30/firejail/issues/1139
)browser-allow-drm yes
/browser-disable-u2f no
infirejail.config
to allow DRM/U2F in browsers.--profile=PROFILENAME
to set the right profile. (Only relevant for AppImages)I think the issue is here:
Send ARP probe:
Received gratuitous ARP
Code:
If I'm reading this correctly:
if packet length is to small, continue if proto type is not arp continue copy arp header if arp code is not 2 (reply) continue compare target mac received to probe sender mac, if not the same continue (the probe sender mac is 02:ba:15:00:00:10, the grat arp target mac is 02:ba:15:00:00:10, so it moves to next step) compare target ip received to probe sent IP, if not continue (the probe sent IP source 0.0.0.0, the grat arp had a target ip 0.0.0.0 soe it moves to the next step) return -1 (ARP probe failed)
(for probe responses, shouldbe be checking target or source, ie wouldn't the arp reply of an 'already-used' IP address have it's IP/MAC in the ARP sender field instead of target field Suspect maybe it should be:
if (memcmp(ifr.ifr_hwaddr.sa_data, hdr.sender_mac, 6) != 0)
and
memcpy(&ip, hdr.sender_ip, 4)
instead