summaryrefslogtreecommitdiffstats
path: root/config/chroot_local-includes/usr/local/lib/tails-spoof-mac
blob: b43811cd33400cb9ce471f936913afcf2246f466 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/bin/sh

set -e
set -u

# This script spoofs or resets the MAC address of all NICs given as
# arguments according to the setting in Tails Greeter. The default (i.e
# before Tails Greeter has been run) is to enable MAC spoofing.

. /usr/local/lib/tails-shell-library/hardware.sh
. /usr/local/lib/tails-shell-library/log.sh
. /usr/local/lib/tails-shell-library/tails-greeter.sh

# Get LIVE_USERNAME
. /etc/live/config.d/username.conf

. /usr/bin/gettext.sh
TEXTDOMAIN="tails"
export TEXTDOMAIN

stop_and_disable_NM() {
   for s in NetworkManager-dispatcher.service \
            NetworkManager-wait-online.service \
            NetworkManager.service; do
       systemctl stop "${s}"
       systemctl disable "${s}"
       systemctl mask "${s}"
   done
   log "Networking disabled"
}

show_notification() {
    # We must wait until all the facilities necessary for showing the
    # notification to the Live user is available to prevent it from
    # getting lost.
    until pgrep -u "${LIVE_USERNAME}" '^ibus-daemon' >/dev/null ; do
        sleep 1
    done
    # The above doesn't seem to be enough. The best we can do seems to
    # be to statically wait a bit longer. The amount chosen is just
    # arbitrarily picked, and may not work on slow hardware or even
    # DVD boot, but should at least work in our automated test suite.
    sleep 10
    /usr/local/sbin/tails-notify-user "${1}" "${2}" 0
}

notify_panic_success() {
    local nic
    local nic_name
    nic="${1}"
    nic_name="${2}"
    show_notification "`gettext \"Network card \\\${nic} disabled\"`" \
"`eval_gettext \"MAC spoofing failed for network card \\\${nic_name} (\\\${nic}) so it is temporarily disabled.
You might prefer to restart Tails and disable MAC spoofing.\"`"
}

notify_panic_failure() {
    local nic
    local nic_name
    nic="${1}"
    nic_name="${2}"
    show_notification "`gettext \"All networking disabled\"`" \
"`eval_gettext \"MAC spoofing failed for network card \\\${nic_name} (\\\${nic}). The error recovery also failed so all networking is disabled.
You might prefer to restart Tails and disable MAC spoofing.\"`"
}

mac_spoof_panic() {
    local nic
    local module
    local nic_name
    local unload_success
    nic=${1}
    if ! /sbin/ip link set dev "${nic}" down; then
        log "Failed to down NIC ${nic} in panic mode."
    fi
    module=$(get_module_used_by_nic "${nic}")
    nic_name="$(get_name_of_nic ${nic})"
    echo "install ${module} /bin/true" >> \
         /etc/modprobe.d/"${module}"-blacklist.conf
    unload_module_and_rev_deps "${module}" || :
    if nic_exists "${nic}"; then
        log "Failed to unload module ${module} of NIC ${nic}."
        stop_and_disable_NM
        notify_panic_failure "${nic}" "${nic_name}" &
    else
        log "Successfully unloaded module ${module} of NIC ${nic}."
        notify_panic_success "${nic}" "${nic_name}" &
    fi
}

spoof_mac() {
    local msg
    set +e
    msg="$(macchanger -e "${1}" 2>&1)"
    ret="${?}"
    set -e
    if [ "${ret}" != 0 ]; then
        log "macchanger failed for NIC ${1}, returned ${ret} and said: ${msg}"
        return 1
    fi
}

set_log_tag spoof-mac

NIC="${1}"

if ! mac_spoof_is_enabled; then
    exit 0
fi

log "Trying to spoof MAC address of NIC ${NIC}..."

if ! nic_exists "${NIC}"; then
    log "NIC ${NIC} doesn't exist, skipping"
    exit 1
fi

OLD_MAC="$(get_current_mac_of_nic "${NIC}")"

# There is a 1/2^24 chance macchanger will randomly pick the real MAC
# address. We try to making it really unlikely repeating it up to
# three times. Theoretically speaking this leaks information about the
# real MAC address at each occasion but actually leaking the real MAC
# address will be more serious in practice.
for i in 1 2 3; do
    if ! spoof_mac "${NIC}"; then
        # If our MAC spoofing primitive fails, we fail safe by forcing
        # us to enter into panic mode.
        unset NEW_MAC
        break
    fi
    NEW_MAC="$(get_current_mac_of_nic "${NIC}")"
    if [ "${OLD_MAC}" != "${NEW_MAC}" ]; then
        break
    fi
done

# MAC spoofing fail-safe: if $NIC's MAC address isn't spoofed at this
# point we have to take some drastic measures in order to prevent
# potential leaks.
if [ -z "${OLD_MAC:-}" ] || [ -z "${NEW_MAC:-}" ] || \
   [ "${OLD_MAC:-}" = "${NEW_MAC:-}" ]
then
    log "Failed to spoof MAC address of NIC ${NIC}. Going into panic mode."
    if ! mac_spoof_panic "${NIC}"; then
        # If mac_spoof_panic() fails we're quite screwed, so we kill
        # NetworkManager without notification to do our best to
        # prevent a MAC address leak.
        log "Panic mode failed for NIC ${NIC}."
        stop_and_disable_NM
    fi
    exit 1
fi

log "Successfully spoofed MAC address of NIC ${NIC}"