Here is an example C code showing how to turn interfaces up and down w/ ioctl(netdevice) or (rt)netlink
The Linux man-pages project
netlink(7) netlink(3)
rtnetlink(7) rtnetlink(3)
netdevice(7)
so_q_5094495.c
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h> // getuid()
// netlink
#include <linux/rtnetlink.h>
// ioctl
#include <net/if.h>
#include <netinet/in.h> // IPPROTO_UDP
#include <sys/ioctl.h>
int ioctlfd=-1;
int netlinkfd=-1;
typedef struct {
struct nlmsghdr nh;
struct ifinfomsg ifi;
} Req_link;
void ioctl_init(){
ioctlfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
assert(ioctlfd==3);
}
void ioctl_end(){
close(ioctlfd);
ioctlfd=-1;
}
void ioctl_flags(const bool up,const char *const dev){
assert(0==getuid());
struct ifreq ifr={};
strncpy(ifr.ifr_name,dev,IFNAMSIZ);
assert(0==ioctl(ioctlfd,SIOCGIFFLAGS,&ifr));
if(up) ifr.ifr_flags|=IFF_UP;
else ifr.ifr_flags&=(~((short)IFF_UP));
assert(0==ioctl(ioctlfd,SIOCSIFFLAGS,&ifr));
}
void netlink_init(){
netlinkfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
assert(netlinkfd==3);
assert(0==bind(netlinkfd,(struct sockaddr*)(&(struct sockaddr_nl){
.nl_family=AF_NETLINK,
.nl_pad=0,
.nl_pid=getpid(),
.nl_groups=0
}),sizeof(struct sockaddr_nl)));
}
void netlink_end(){
assert(0==close(netlinkfd));
netlinkfd=-1;
}
void netlink_flags(const bool up,const char *const dev){
assert(0==getuid());
assert(dev&&strlen(dev));
const unsigned index=if_nametoindex(dev);
assert(index>0);
assert(sizeof(Req_link)==send(netlinkfd,&(Req_link){
.nh={
.nlmsg_len=NLMSG_LENGTH(sizeof(struct ifinfomsg)),
.nlmsg_type=RTM_NEWLINK,
.nlmsg_flags=NLM_F_REQUEST,
.nlmsg_seq=0,
.nlmsg_pid=getpid()
},
.ifi={
.ifi_family=AF_UNSPEC,
.ifi_type=0,
.ifi_index=index,
.ifi_flags=up?IFF_UP:0,
// https://www.spinics.net/lists/netdev/msg598191.html
.ifi_change=IFF_UP
}
},sizeof(Req_link),0));
}
int main(const int argc,const char *argv[]){
assert(argc==3+1);
void (*flags)(const bool,const char *const)=NULL;
void (*init)()=NULL;
void (*end)()=NULL;
assert(strlen(argv[1]));
if(0==strcmp("ioctl",argv[1])){
init=&ioctl_init;
flags=&ioctl_flags;
end=&ioctl_end;
}else if(0==strcmp("netlink",argv[1])){
init=&netlink_init;
flags=&netlink_flags;
end=&netlink_end;
}else{
assert(false);
}
bool up=false;
if(0==strcmp("down",argv[2])) up=true;
else if(0==strcmp("up",argv[2])) up=false;
else assert(false);
assert(strlen(argv[3])&&strlen(argv[3])<=IFNAMSIZ-1);
(*init)();
(*flags)(up,argv[3]);
(*end)();
return 0;
}
Run
$ gcc -Wall -std=gnu11 so_q_5094495.c
$ sudo ./a.out netlink up enp0s31f6; ip link show enp0s31f6 | grep -o '<.*>'
<BROADCAST,MULTICAST>
$ sudo ./a.out netlink down enp0s31f6; ip link show enp0s31f6 | grep -o '<.*>'
<NO-CARRIER,BROADCAST,MULTICAST,UP>
$ sudo ./a.out ioctl up enp0s31f6; ip link show enp0s31f6 | grep -o '<.*>'
<BROADCAST,MULTICAST>
$ sudo ./a.out ioctl down enp0s31f6; ip link show enp0s31f6 | grep -o '<.*>'
<NO-CARRIER,BROADCAST,MULTICAST,UP>