以编程方式启用/禁用UNIX网络接口

时间:2011-02-23 17:28:23

标签: c unix network-programming posix

发布了很多非常相似的问题,但它们都是针对Windows的 - 我想知道如何(如果可能的话)我可以拥有我的C程序(在linux上以root身份运行)禁用网络接口它不再接收任何数据包。

如果有人可以告诉我我需要做什么功能,那就太好了,但如果你可以将我链接到一个示例脚本或教程(例如)关闭并重新打开网络界面,那就更好了。

6 个答案:

答案 0 :(得分:4)

对于Linux,使用MNL和RTNL协议的知识都很容易实现:

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

在Unices或其他操作系统上,只有特定于操作系统的调用和/或过时的ioctl调用可用,后者无法正确表达每个接口的Linux多个地址,因此严重的程序不会在其上使用它平台。

答案 1 :(得分:2)

没有一个完整的例子,但是下面的关键词应该让你入门(至少在Linux上,不确定其他版本的Unix):

  

ioctl,SIOCSIFFLAGS,IFF_UP

在显示相关API时,可能会使用以下内容:http://www.google.com/codesearch/p?hl=en#2--Ws53NXRc/src/ifdown.c

答案 2 :(得分:1)

在Linux上,您可以使用ifdown。我不知道对其他unix有多便携。

答案 3 :(得分:1)

在我使用的Linux和大多数基于Unix的系统上,ifconfig <interface> up/down用于启用或关闭接口。在不执行ifconfig的情况下,不确定是否有可用的C例程。

答案 4 :(得分:1)

在Linux上,命令ip link set down dev ethX不会比你想要的更多或更少。如果你在那个平台上,我建议你把这个程序叫做你的工作。

如果您想自己动手,C api对此并不是一件简单的事情。 您可以深入了解iproute来源,了解它的作用。

检查@ user611775的答案,了解如何在C中执行此操作的优秀示例。

如果您使用的是另一台Unix,那么每种特定风味的答案可能会有所不同。

答案 5 :(得分:0)

这是一个示例C代码,显示如何使用ioctl(netdevice)或(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;

}

运行

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