tails-spoof-mac 5.06 KB
Newer Older
1
#!/bin/sh
2

3
set -e
4
set -u
5

Tails developers's avatar
Tails developers committed
6
7
8
# 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.
9
10
11

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

14
15
16
# Get LIVE_USERNAME
. /etc/live/config.d/username.conf

17
18
19
20
# Get LANG
. /etc/default/locale
export LANG

21
22
23
24
. /usr/bin/gettext.sh
TEXTDOMAIN="tails"
export TEXTDOMAIN

25
stop_and_disable_NM() {
26
27
28
29
30
   for s in NetworkManager-dispatcher.service \
            NetworkManager-wait-online.service \
            NetworkManager.service; do
       systemctl stop "${s}"
       systemctl disable "${s}"
31
       systemctl mask "${s}"
32
33
   done
   log "Networking disabled"
34
35
}

36
show_notification() {
37
38
39
    # We must wait until all the facilities necessary for showing the
    # notification to the Live user is available to prevent it from
    # getting lost.
40
    until pgrep -u "${LIVE_USERNAME}" '^ibus-daemon' >/dev/null ; do
41
42
        sleep 1
    done
43
44
45
46
47
    # 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
48
49
50
51
52
53
54
55
    /usr/local/sbin/tails-notify-user "${1}" "${2}" 0
}

notify_panic_success() {
    local nic
    local nic_name
    nic="${1}"
    nic_name="${2}"
intrigeri's avatar
intrigeri committed
56
    show_notification "$(eval_gettext "Network card \${nic} disabled")" \
57
58
"$(eval_gettext "MAC address anonymization failed for network card \${nic_name} (\${nic}) so it is temporarily disabled.
You might prefer to restart Tails and disable MAC address anonymization.")"
59
60
61
62
63
64
65
}

notify_panic_failure() {
    local nic
    local nic_name
    nic="${1}"
    nic_name="${2}"
intrigeri's avatar
intrigeri committed
66
    show_notification "$(gettext "All networking disabled")" \
67
68
"$(eval_gettext "MAC address anonymization 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 address anonymization.")"
69
70
71
72
73
74
75
}

mac_spoof_panic() {
    local nic
    local module
    local nic_name
    nic=${1}
Tails developers's avatar
Tails developers committed
76
77
78
    if ! /sbin/ip link set dev "${nic}" down; then
        log "Failed to down NIC ${nic} in panic mode."
    fi
79
    module=$(get_module_used_by_nic "${nic}")
intrigeri's avatar
intrigeri committed
80
    nic_name="$(get_name_of_nic "${nic}")"
81
82
    echo "install ${module} /bin/true" >> \
         /etc/modprobe.d/"${module}"-blacklist.conf
Tails developers's avatar
Tails developers committed
83
    unload_module_and_rev_deps "${module}" || :
84
    if nic_exists "${nic}"; then
85
        log "Failed to unload module ${module} of NIC ${nic}."
86
        stop_and_disable_NM
87
        notify_panic_failure "${nic}" "${nic_name}" &
88
89
    else
        log "Successfully unloaded module ${module} of NIC ${nic}."
90
        notify_panic_success "${nic}" "${nic_name}" &
91
92
93
    fi
}

94
spoof_mac() {
95
    local msg
96
97
98
99
100
    set +e
    msg="$(macchanger -e "${1}" 2>&1)"
    ret="${?}"
    set -e
    if [ "${ret}" != 0 ]; then
anonym's avatar
anonym committed
101
        log "macchanger failed for NIC ${1}, returned ${ret} and said: ${msg}"
102
        return 1
103
104
105
106
107
    fi
}

set_log_tag spoof-mac

Tails developers's avatar
Tails developers committed
108
NIC="${1}"
109
110
111
112
113
114
115

if ! mac_spoof_is_enabled; then
    exit 0
fi

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

Tails developers's avatar
Tails developers committed
116
if ! nic_exists "${NIC}"; then
117
118
119
120
    log "NIC ${NIC} doesn't exist, skipping"
    exit 1
fi

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

123
124
125
126
127
# 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.
128
# shellcheck disable=SC2034
129
for i in 1 2 3; do
130
131
132
133
134
135
    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
136
137
138
139
140
    NEW_MAC="$(get_current_mac_of_nic "${NIC}")"
    if [ "${OLD_MAC}" != "${NEW_MAC}" ]; then
        break
    fi
done
141

142
143
144
# 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.
145
if [ -z "${OLD_MAC:-}" ] || [ -z "${NEW_MAC:-}" ] || \
146
147
   [ "${OLD_MAC:-}" = "${NEW_MAC:-}" ] || \
   grep -qs -w 'debug=test_mac_spoof_panic' /proc/cmdline
148
then
149
150
151
152
153
    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.
154
        log "Panic mode failed for NIC ${NIC}."
155
        stop_and_disable_NM
Tails developers's avatar
Tails developers committed
156
    fi
157
158
159
160
161
    # Wait for the notification subprocesses to exit before quitting to
    # prevent them being interrupted by underlying process manager (udev)
    # once we quit. Note that it could make us wait indefinitely.
    # However, udev will interrupt rules tasks after 120 seconds.
    wait
162
    exit 1
163
fi
164
165

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