Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Hi I made bash script to put down my interface, change MAC address and get it up again.

#!/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

The problem is that it does not work. Immediately after putting down eth0 /sys/class/net/eth0/operstate changes to down but it seems like it isn't down yet. I takes like 10 seconds to put down interface eth0 so only way to make it work is to add sleep 10 after putting down eth0.

So my question is how to check if eht0 is really down?

//EDIT

It's like command ifconfig eth0 up is used to early because it never gets up with new MAC address. I need to put it down, wait 10 s, change MAC and put it back again. I suspect that putting down eth0 takes few seconds and putting it up again too early does not work.

//EDIT 2

I checked MAC address again and it seems that it's changed, so now I think that it could be something with DNS because when I'm using ping on google I get unknown host. But same method with sleep 10 does work.

// EDIT 3

After using script without sleep 10 I tried using 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)

//EDIT 4 SUM UP

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

Why sleep 10 matters?

// EDIT 5

Its getting quite weird. When I use sleep it works fine. When I try without sleep it looks like IP is ok, interface is up, but network does not work. When I try put down eth0 with sudo ifconfig eth0 down after few seconds my OS (ubuntu 12.10) reconects me automaticly with my old MAC address and I get new IP. With second use of sudo ifconfig eth0 down I'm able to fully put 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)

//EDIT 6

I've tried solution suggested by @Moreaki but the same thing happens. Script runs around one second but my network is unreachable after using it. This is the code from @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

After using it I get:

piotrek@piotrek-Vostro-2520:~$ ./mac_test.sh 
up
Putting down eth0
New state: down

And after trying 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

//EDIT 7

Using routing script from @Moreaki my routing before changing mac address looks like this:

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

And after changing MAC address using my script with 10s delay:

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

Routing after using @Moreaki script:

piotrek@piotrek-Vostro-2520:~$ ./routing.sh
Destination        Gateway         Source             Iface    R_Type RT_table

@Moreaki also suggested to comment line sudo ip addr flush dev ${INTF} but I still get connect: Network is unreachable. My routing after using his script with commented line looks like this:

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
share|improve this question
1  
In what way do you mean that the interface is not down when sysfs reports it as down? ifconfig eth0 down almost certainly makes a call to the kernel to effect the change, and sysfs reads the internal kernel data structures, so I don't see how sysfs could report the interface being down when it really is not. Maybe you are referring to something related but different? –  Michael Kjörling Aug 19 '13 at 8:43
    
It's like command ifconfig eth0 up is used to early because it never gets up with new MAC address. I need to put it down, wait 10 s, change MAC and put it back again. See my edited post –  piotrekkr Aug 19 '13 at 8:52
    
So your question is really "why does the sequence ifconfig eth0 down, ifconfig eth0 hw ether ..., ifconfig eth0 up with no intervening delays not change the MAC address on eth0, when adding a delay between down and ether does?", correct? –  Michael Kjörling Aug 19 '13 at 8:54
    
Use grep -q "up" /sys/class/net/eth0/operstate && sudo ifdown eth0 This is a more accurate way of doing checks in bash. Also use ifdown eth0 instead. This uses ifconfig to configure the interfaces. –  val0x00ff Aug 19 '13 at 8:57
    
@MichaelKjörling I check MAC again and it seems like it is changed so now I think it's more like DNS problem than interface. I get like unknown host when trying to ping google. –  piotrekkr Aug 19 '13 at 9:05

3 Answers 3

Can't yet comment, so I hope my take will shed some light on your observed behaviour. In general I wouldn't recommend using ifconfig to fiddle with your interface settings under Linux. It has de facto been "deprecated" over ten years ago. Having said that, obviously it should still work, as distros continue to ship ifconfig and route.

Could you check if this approach changes the behaviour you are seeing:

#!/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

ADDENDUM 1: Reading your feedback, you might want to offer more information about your routing setup. I have dug up some old scripts I wrote over a decade ago. This one should show the routing table output similar to netstat (root is needed to run this):

#!/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)
share|improve this answer
    
If ifconfig is deprecated, what should we use instead? –  WChargin Aug 24 '13 at 21:42
1  
The iproute2 framework that was introduced in kernel 2.1.x. You can find more documentation here. –  Moreaki Aug 24 '13 at 21:55
    
@Moreaki Thanks for your suggestion but It didn't work. See my last edit. Your script works for like one second and after using it my network is unreachable. –  piotrekkr Aug 28 '13 at 7:13
    
Well, from what I see, unless you add an IP address when you fire you device up again (after flushing all IP addresses), things won't work. So, either add an IP address into the script or do not execute the line sudo ip addr flush dev ${INTF} in my snippet, as I hinted in my comment. –  Moreaki Aug 28 '13 at 10:25
    
@Moreaki I've added routing in my last edit. Commenting line that you suggested didn't work. I'll be grateful for other suggestions. –  piotrekkr Aug 29 '13 at 7:44

The delay in bringing down the interface is likely related to the driver and/or hardware for the interface. If that is correct, then there is no standard way to know when the driver or hardware have truly put the interface down.

Reading through the rest of the troubleshooting more, it sounds like there could be a competing process in play - especially the part about the interface coming back up "on its own". Perhaps there is a tool that runs and puts the interface back up after the attempt to take it down?

That would be a little tricky to detect, but not impossible. I can't think of any quick and easy way to suggest that you could detect it.

share|improve this answer

I don't think a delay is required. Before putting the interface down, you should be able to physically disconnect from the old MAC address. I'm on wireless at the moment, so I can't test this out right now, but look at the ifconfig --help. Something like this?:

ifconfig <interface> del <address>

On wireless, when I disconnect, I run a little script that clears everything, including the AP's MAC address:

sudo dhcpcd --release "$INTERFACE"
sudo iwconfig "$INTERFACE" essid off
sudo iwconfig "$INTERFACE" ap off
sudo ifconfig "$INTERFACE" down
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.