开发者

Programmatically enable/disable UNIX network interface

T开发者_运维技巧here are a lot of very similar questions posted, but they are all for windows - I want to know how (if it is possible) I can have my C program (run as root, on linux) disable the network interface so that it is no longer receiving any packets.

If someone can tell me what functions I need to do this, that would be great, but even better if you can link me to an example script or tutorial somewhere that (exempli gratia) turns the network interface off and on again.


Don't have a complete example, but the following key words should get you started (on Linux at least, not sure about other flavours of Unix):

ioctl, SIOCSIFFLAGS, IFF_UP

The following might be of use as far as showing the relevant APIs: http://www.google.com/codesearch/p?hl=en#2--Ws53NXRc/src/ifdown.c


For Linux, all easily doable with MNL and knowledge of the RTNL protocol:

http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=blob;f=examples/rtnl/rtnl-link-set.c;hb=HEAD

On Unices or other operating systems, only a OS-specific call and/or the archaic ioctl call is available, the latter of which cannot express Linux multiple addresses per interface properly, so serious programs do not make use of it on that platform.


On Linux, you can use ifdown. I don't know how portable that is to other unixes.


On both Linux and most Unix based systems I've used, ifconfig <interface> up/down is used to bring an interface up or down. Not sure if there is a C routine available for this without execing ifconfig.


On Linux, the command ip link set down dev ethX does no more or less then what you want. I'd suggest calling this program to do your work if you're on that platform.

If you want to do it yourself, the C api for this is not a simple thing. You could dive into the iproute source to find out what it does.

Check @user611775's answer for an excellent example of how to do it in C.

If you're on another Unix, the answer is likely going to to be different for each specific flavour.


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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜