netblue30 / fdns

Firejail DNS-over-HTTPS Proxy Server
GNU General Public License v3.0
115 stars 29 forks source link

What's the best way to start fdns instances for firejail as a user? #51

Closed rusty-snake closed 3 years ago

rusty-snake commented 3 years ago

If want to use fdns together with firejail --dns, so that a sandbox has it's own resolver. You need to get root to start fdns. That's a bit annoying if you need to enter your PW and bad to script if you use sudo. So what can be done to do this automatically.

  1. obvious: add a NOPASSWD rule to sudo. However you wound need to create new rules for every used --withelist argument because sudo has no support for regexp and * matches everything (including spaces). Example rule: john ALL=(ALL) NOPASSWD: /usr/bin/fdns --proxy-addr=127.70.74.[0-9]

  2. I created a heavy SUID-binary which starts fdns https://github.com/rusty-snake/fdns4users. However, that's still no good solution as you don't want more suids on your system.

Has anyone found a good solution? Polkit maybe.

glitsj16 commented 3 years ago

Has anyone found a good solution? Polkit maybe.

Interesting topic. I do indeed think polkit might be your safest option. Something like the below might work (untested).


$ cat /etc/polkit-1/actions/org.netblue30.fdns.policy
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
 "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
<policyconfig>
  <vendor>netblue30</vendor>
  <vendor_url>https://github.com/netblue30</vendor_url>

  <action id="org.netblue30.fdns.start">
    <description>Start fdns</description>
    <message>Authentication is required to start fdns</message>
    <icon_name>foo</icon_name>
    <defaults>
      <allow_any>auth_admin</allow_any>
      <allow_inactive>auth_admin</allow_inactive>
      <allow_active>auth_admin</allow_active>
    </defaults>
  </action>

</policyconfig>

$ cat /etc/polkit-1/rules.d/30-fdns.rules
/* Allow members of the fdns group to start the daemon
     without password authentication, similar to sudo NOPASSWD: */
polkit.addRule(function(action, subject) {
    if ((action.id == "org.netblue30.fdns.start")
        && subject.isInGroup("fdns")) {
       return polkit.Result.YES;
   }
});
rusty-snake commented 3 years ago

I'm need to read more about polkit. Anyway, here is my first attempt.

Actually a rule for pkexec in enough to execute pkexec fdns --proxy-addr=127.70.74.68 --whitelist=github.com without a password-prompt.

/etc/polkit-1/rules.d/60-fdns.rules:

polkit.addRule(function(action, subject) {
    var re = new RegExp("^/usr/bin/fdns --proxy-addr=127\\.70\\.74\\.[0-9]{1,3}( --whitelist=[A-Za-z0-9._-]+)*$");
    if (action.id === "org.freedesktop.policykit.exec" &&
        action.lookup("program") === "/usr/bin/fdns" &&
        re.test(action.lookup("command_line")) &&
        subject.user === "rusty-snake" && subject.local && subject.active) {
        return polkit.Result.YES;
    }
});

NOTE: This does not work for Debian/Ubuntu because they still ship polkit 0.105 which uses PKLA-rules. Apparently they have some security concerns about using Javascript for that. But I can't understand it, javascript is the first word that comes to my mind when I hear security :clown_face:.

rusty-snake commented 3 years ago

Ok, I go with polkit.

[UPDATE: https://github.com/rusty-snake/fdns4users#example-for-polkit]

polkit.addRule(function(action, subject) {
    const USER = "john";
    const PROGRAM = "/usr/bin/fdns";

    const IP = "127\\.70\\.74\\.[0-9]{1,3}";
    const PROXY_ADDR = `--proxy-addr=${IP}`;
    const WHITELIST = `--whitelist=[A-Za-z0-9._-]+`;
    const ZOM_WHITELIST = `( ${WHITELIST})*`;
    const RE = new RegExp(`^${PROGRAM} ${PROXY_ADDR}${ZOM_WHITELIST}$`);

    // Debugging: uncomment to see the final RegExp
    //polkit.log(RE.toString());

    if (action.id === "org.freedesktop.policykit.exec" &&
        action.lookup("program") === PROGRAM &&
        RE.test(action.lookup("command_line")) &&
        subject.user === USER && subject.local && subject.active) {
        return polkit.Result.YES;
    }
});
#!/bin/bash

PROXY_ADDR=127.70.74.68
FDNS_LOG_FILE="$HOME/fdns-log.txt"

ALLOWED_DOMAINS=(example.com)

whitelist=()
for domain in "${ALLOWED_DOMAINS[@]}"; do
        whitelist+=("--whitelist=$domain")
done

echo -e "\n\n===> fdns --proxy-addr=$PROXY_ADDR ${whitelist[@]} <===\n" >> $FDNS_LOG_FILE
pkexec fdns "--proxy-addr=$PROXY_ADDR" "${whitelist[@]}" >> $FDNS_LOG_FILE &

sleep 2s

firejail --dns=$PROXY_ADDR thunderbird

kill $(jobs -p)
rusty-snake commented 3 years ago

kill $(jobs -p)

Wait, I can not kill processes belonging to an other user.