你好,我制作了 bash 脚本来放下我的接口,更改 MAC 地址并再次启动它。
#!/bin/bash
INTERFACE_STATUS=$( cat /sys/class/net/eth0/operstate )
echo "$INTERFACE_STATUS"
if [ "$INTERFACE_STATUS" == "up" ]
then
echo "Putting down eth0"
sudo ifconfig eth0 down
# putting down eth0 works only when I sleep 10 seconds after using command
#sleep 10
echo "$( cat /sys/class/net/eth0/operstate )"
# TRIES=0
# while [ "$( cat /sys/class/net/eth0/operstate )" == "up" ]
# do
# sleep 1
# TRIES=$(($TRIES + 1))
# if [ "$TRIES" == "7" ]
# then
# echo Could not put down eth0
# exit 1
# fi
# done
fi
sudo ifconfig eth0 hw ether "91:91:91:91:91:91"
sudo ifconfig eth0 up
问题是它不起作用。放下 eth0 后立即/sys/class/net/eth0/operstate
更改为,down
但似乎尚未关闭。我花了大约 10 秒来放下接口 eth0,所以让它工作的唯一方法是在sleep 10
放下 eth0 后添加。
所以我的问题是如何检查 eht0 是否真的已关闭?
//编辑
这就像命令ifconfig eth0 up
很早就被使用一样,因为它永远不会获得新的 MAC 地址。我需要把它放下,等待 10 秒,更改 MAC,然后再放回去。我怀疑放下 eth0 需要几秒钟的时间,并且过早地再次放下它是行不通的。
//编辑2
我再次检查了 MAC 地址,似乎它已更改,所以现在我认为它可能与 DNS 相关,因为当我在 google 上使用 ping 时,我得到未知主机。但同样的方法确实sleep 10
有效。
// 编辑3
使用脚本后,sleep 10
我尝试使用 ping:
piotrek@piotrek-Vostro-2520:~$ ping 212.77.100.101
connect: Network is unreachable
piotrek@piotrek-Vostro-2520:~$ ping -n 212.77.100.101
connect: Network is unreachable
piotrek@piotrek-Vostro-2520:~$ ifconfig
eth0 Link encap:Ethernet HWaddr 08:3e:8e:2d:36:55
inet addr:10.36.253.122 Bcast:10.36.253.255 Mask:255.255.255.0
inet6 addr: fe80::a3e:8eff:fe2d:3655/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:74297 errors:0 dropped:0 overruns:0 frame:0
TX packets:38597 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:32417366 (32.4 MB) TX bytes:5201537 (5.2 MB)0
collisions:0 txqueuelen:1000
RX bytes:32417366 (32.4 MB) TX bytes:5201537 (5.2 MB)
//编辑4总结
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down; sudo ifconfig eth0 hw ether 08:3e:8e:2d:36:55 ; sudo ifconfig eth0 up
piotrek@piotrek-Vostro-2520:~$ ping -n 212.77.100.101
connect: Network is unreachable
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down; sleep 10; sudo ifconfig eth0 hw ether 08:3e:8e:2d:36:55 ; sudo ifconfig eth0 up
piotrek@piotrek-Vostro-2520:~$ ping -n 212.77.100.101
PING 212.77.100.101 (212.77.100.101) 56(84) bytes of data.
64 bytes from 212.77.100.101: icmp_req=1 ttl=246 time=8.91 ms
64 bytes from 212.77.100.101: icmp_req=2 ttl=246 time=8.76 ms
64 bytes from 212.77.100.101: icmp_req=3 ttl=246 time=8.52 ms
^C
--- 212.77.100.101 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 8.523/8.734/8.917/0.194 ms
为什么sleep 10
重要?
// 编辑5
它变得很奇怪。当我使用sleep
它时效果很好。当我尝试不使用时,sleep
看起来 IP 没问题,接口已启动,但网络无法工作。当我尝试在几秒钟后放下时,eth0
我sudo ifconfig eth0 down
的操作系统(ubuntu 12.10)会自动将我与我的设备重新连接旧的MAC地址我得到了新的IP。第二次使用sudo ifconfig eth0 down
我就可以完全放下了eth0
。
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down; sleep 10; sudo ifconfig eth0 hw ether 08:3e:8e:2d:36:55 ; sudo ifconfig eth0 up
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig
eth0 Link encap:Ethernet HWaddr 08:3e:8e:2d:36:55
inet addr:10.36.253.241 Bcast:10.36.253.255 Mask:255.255.255.0
inet6 addr: fe80::a3e:8eff:fe2d:3655/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:439341 errors:0 dropped:0 overruns:0 frame:0
TX packets:224187 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:400718780 (400.7 MB) TX bytes:26246307 (26.2 MB)
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down; sudo ifconfig eth0 hw ether 08:3e:8e:2d:36:55 ; sudo ifconfig eth0 up
piotrek@piotrek-Vostro-2520:~$ ping -n 212.77.100.101
connect: Network is unreachable
piotrek@piotrek-Vostro-2520:~$ ifconfig
eth0 Link encap:Ethernet HWaddr 08:3e:8e:2d:36:55
inet addr:10.36.253.241 Bcast:10.36.253.255 Mask:255.255.255.0
inet6 addr: fe80::a3e:8eff:fe2d:3655/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:439656 errors:0 dropped:0 overruns:0 frame:0
TX packets:224321 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:400827185 (400.8 MB) TX bytes:26267012 (26.2 MB)
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down
piotrek@piotrek-Vostro-2520:~$ ifconfig
eth0 Link encap:Ethernet HWaddr e0:db:55:97:de:cc
inet addr:10.36.253.122 Bcast:10.36.253.255 Mask:255.255.255.0
inet6 addr: fe80::e2db:55ff:fe97:decc/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:440302 errors:0 dropped:0 overruns:0 frame:0
TX packets:224862 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:401129508 (401.1 MB) TX bytes:26323176 (26.3 MB)
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down
piotrek@piotrek-Vostro-2520:~$ ifconfig eth0
eth0 Link encap:Ethernet HWaddr e0:db:55:97:de:cc
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:440437 errors:0 dropped:0 overruns:0 frame:0
TX packets:224881 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:401147424 (401.1 MB) TX bytes:26326068 (26.3 MB)
//编辑6
我已经尝试过@Moreaki 建议的解决方案,但同样的事情发生了。脚本运行大约一秒,但使用它后我的网络无法访问。这是来自@Moreaki 的代码:
#!/usr/bin/env bash
INTF=eth0
INTERFACE_STATUS=$(cat /sys/class/net/${INTF}/operstate)
echo "$INTERFACE_STATUS"
if [ "$INTERFACE_STATUS" == "up" ]; then
echo "Putting down ${INTF}"
# if you need to remove all IP addresses associated with ${INTF}
sudo ip addr flush dev ${INTF}
# set the interface status down
sudo ip link set dev ${INTF} down
# flush neighbour cache
sudo ip neigh flush dev ${INTF}
# flush routing cache entries pertaining to ${INTF}
sudo ip route flush table cache dev ${INTF}
echo "New state: $(cat /sys/class/net/${INTF}/operstate)"
fi
sudo ip link set dev ${INTF} address "08:3e:8e:2d:36:55"
sudo ip link set dev ${INTF} up
使用它后我得到:
piotrek@piotrek-Vostro-2520:~$ ./mac_test.sh
up
Putting down eth0
New state: down
尝试 ping 后:
piotrek@piotrek-Vostro-2520:~$ ping google.com
ping: unknown host google.com
piotrek@piotrek-Vostro-2520:~$ ping 8.8.8.8
connect: Network is unreachable
//编辑7
使用来自 @Moreaki 的路由脚本,在更改 mac 地址之前我的路由如下所示:
piotrek@piotrek-Vostro-2520:~$ ./routing.sh
Destination Gateway Source Iface R_Type RT_table
default 10.36.253.1 10.36.253.122 eth0 main
10.36.253.0/24 0.0.0.0 10.36.253.122 eth0 main
169.254.0.0/16 0.0.0.0 10.36.253.122 eth0 main
并在使用更改MAC地址后我的脚本延迟了 10 秒:
piotrek@piotrek-Vostro-2520:~$ ./routing.sh
Destination Gateway Source Iface R_Type RT_table
default 10.36.253.1 10.36.253.241 eth0 main
10.36.253.0/24 0.0.0.0 10.36.253.241 eth0 main
169.254.0.0/16 0.0.0.0 10.36.253.241 eth0 main
使用@Moreaki脚本后的路由:
piotrek@piotrek-Vostro-2520:~$ ./routing.sh
Destination Gateway Source Iface R_Type RT_table
@Moreaki 还建议评论行sudo ip addr flush dev ${INTF}
,但我仍然明白connect: Network is unreachable
。使用带有注释行的脚本后我的路由如下所示:
piotrek@piotrek-Vostro-2520:~$ ./routing.sh
Destination Gateway Source Iface R_Type RT_table
10.36.253.0/24 0.0.0.0 10.36.253.122 eth0
答案1
关闭接口的延迟可能与接口的驱动程序和/或硬件有关。如果这是正确的,那么就没有标准方法可以知道驱动程序或硬件何时真正关闭了接口。
仔细阅读其余的故障排除内容,听起来可能存在一个竞争过程,尤其是有关界面“自行”恢复的部分。也许有一个工具可以在尝试关闭界面后运行并恢复界面?
检测起来有点棘手,但并非不可能。我想不出任何快速简便的方法来建议您可以检测到它。
答案2
我认为不需要延迟。在关闭接口之前,您应该能够从物理上断开与旧 MAC 地址的连接。我现在使用的是无线网络,所以现在无法对此进行测试,但请查看 ifconfig --help。像这样的东西?:
ifconfig <interface> del <address>
在无线网络上,当我断开连接时,我运行一个小脚本来清除所有内容,包括 AP 的 MAC 地址:
sudo dhcpcd --release "$INTERFACE"
sudo iwconfig "$INTERFACE" essid off
sudo iwconfig "$INTERFACE" ap off
sudo ifconfig "$INTERFACE" down
答案3
尚无法发表评论,所以我希望我的观点能够对您观察到的行为有所启发。一般来说,我不建议使用 ifconfig 来修改 Linux 下的界面设置。事实上,它在十多年前就已被“弃用”。话虽如此,显然它应该仍然有效,因为发行版继续提供 ifconfig 和路由。
您能否检查一下这种方法是否会改变您所看到的行为:
#!/usr/bin/env bash
INTF=eth0
INTERFACE_STATUS=$(cat /sys/class/net/${INTF}/operstate)
echo "$INTERFACE_STATUS"
if [ "$INTERFACE_STATUS" == "up" ]; then
echo "Putting down ${INTF}"
# if you need to remove all IP addresses associated with ${INTF}
sudo ip addr flush dev ${INTF}
# set the interface status down
sudo ip link set dev ${INTF} down
# flush neighbour cache
sudo ip neigh flush dev ${INTF}
# flush routing cache entries pertaining to ${INTF}
sudo ip route flush table cache dev ${INTF}
echo "New state: $(cat /sys/class/net/${INTF}/operstate)"
fi
sudo ip link set dev ${INTF} address "91:91:91:91:91:91"
sudo ip link set dev ${INTF} up
附录 1:阅读您的反馈后,您可能希望提供有关路由设置的更多信息。我挖出了一些十多年前写的旧脚本。这应该显示类似于以下内容的路由表输出netstat
(需要 root 才能运行此命令):
#!/usr/bin/env bash
# 08/2000: Initial code to beautify iproute2 routing table output
# 08/2013: Updated it for the new decade and removed swearing.
: ${IPTOOL:=/sbin/ip}
: ${DEBUG:=0}
print_format="%-18s %-15s %-18s %-8s %-6s %-10s\n"
if [ "x$1" == "x-v" -o "x$1" == "x--verbose" ]; then
DEBUG=1
fi
dbg_log(){
if [ $DEBUG -eq 1 ]; then
echo "$*"
fi
}
printme(){
if [ "x$via" == "x" -a $src_route -eq 0 ]; then
via="0.0.0.0"
fi
if [ "x$src" == "x" ]; then
src=$(${IPTOOL} addr show dev $dev label $dev | awk '/inet/ {print $2}')
src=${src%%/*}
fi
printf "$print_format" "$net" "$via" "$src" "$dev" "$type" "$table_id"
}
eval_route(){
not_parsed=0
while read net rest; do
if [ $src_route -eq 0 ]; then
src=
type=
fi
table_id="${TABLE_ID}"
dev=
via=
set -- $rest
while [ $# -ne 0 ]; do
case $1 in
proto) shift 1;;
scope) shift 1;;
metric) shift 1;;
dev) shift 1; dev=$1;;
via) shift 1; via=$1;;
src) shift 1; src=$1
# As soon as I've figured out, how to get back the
# interface/label definition from a given src IP
# I will adjust this ugly hack. --rn, 08/2000
if [ "x${src%.*}" != "x${net%.*}" ]; then
dev=$(${IPTOOL} addr show dev $dev to $src | \
awk -v check_ip=${temp_ip%%/*} 'BEGIN {/$check_ip/} END {print $7}')
fi
;;
*) dbg_log "option $1 not parsed"; not_parsed=1;;
esac
shift 1
done
# Check for 'throw, blackhole, unreachable, prohibit'
# Since we only check for non-numeric strings, we have
# to exclude the default target too.
if [ "x${net//[0-9.]/}" == "x$net" -a "x$net" != "xdefault" ]; then
type=${net:0:2}
type=${type~~}
net=$rest
dev="all"
src="0.0.0.0/0"
not_parsed=0
fi
[ $not_parsed -eq 0 ] && printme
not_parsed=0
done < <(${IPTOOL} route show table $TABLE_ID)
}
src_route=0
printf "$print_format" "Destination" "Gateway" "Source" "Iface" "R_Type" "RT_table"
while read RULE_ID rest; do
RULE_ID=${RULE_ID//:/}
fromIP=
toIP=
TABLE_ID=
set -- ${rest}
while [ $# -ne 0 ]; do
case $1 in
from) fromIP=$2 ; shift 2;;
to) toIP=$2 ; shift 2;;
lookup) TABLE_ID=$2; shift 2;;
*) shift 1;;
esac
done
if [ $RULE_ID -ne 0 ]; then
dbg_log "+------------------[RULE: $RULE_ID]------------------+"
if [ "x$fromIP" != "xall" ]; then
src_route=1
src="$IP"
type=SR
fi
eval_route
src_route=0
fi
done < <(${IPTOOL} rule show)