2013-01-16 1 views
2

Y at-il de toute façon ajouter et supprimer des adresses IP d'une interface (comme le bouclage) en C?ajouter et supprimer des adresses IP à une interface en utilisant ioctl ou netlink

J'ai trouvé ioctl et quelques documents expliquant comment faire cela (par exemple this link), mais ils sont tous pour définir les adresses ne pas ajouter et supprimer?

Suite aux suggestions que je courais strace pour ajouter une nouvelle réalimentation et voici les résultats:

$ sudo strace ip addr add 1.2.3.4 dev lo 
execve("/sbin/ip", ["ip", "addr", "add", "1.2.3.4", "dev", "lo"], [/* 17 vars */]) = 0 
brk(0)         = 0x1bab000 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f221ed04000 
access("/etc/ld.so.preload", R_OK)  = -1 ENOENT (No such file or directory) 
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=109414, ...}) = 0 
mmap(NULL, 109414, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f221ece9000 
close(3)        = 0 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\r\0\0\0\0\0\0"..., 832) = 832 
fstat(3, {st_mode=S_IFREG|0644, st_size=14768, ...}) = 0 
mmap(NULL, 2109704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f221e8e0000 
mprotect(0x7f221e8e2000, 2097152, PROT_NONE) = 0 
mmap(0x7f221eae2000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f221eae2000 
close(3)        = 0 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200\30\2\0\0\0\0\0"..., 832) = 832 
fstat(3, {st_mode=S_IFREG|0755, st_size=1811128, ...}) = 0 
mmap(NULL, 3925208, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f221e521000 
mprotect(0x7f221e6d6000, 2093056, PROT_NONE) = 0 
mmap(0x7f221e8d5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x7f221e8d5000 
mmap(0x7f221e8db000, 17624, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f221e8db000 
close(3)        = 0 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f221ece8000 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f221ece7000 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f221ece6000 
arch_prctl(ARCH_SET_FS, 0x7f221ece7700) = 0 
mprotect(0x7f221e8d5000, 16384, PROT_READ) = 0 
mprotect(0x7f221eae2000, 4096, PROT_READ) = 0 
mprotect(0x638000, 4096, PROT_READ)  = 0 
mprotect(0x7f221ed06000, 4096, PROT_READ) = 0 
munmap(0x7f221ece9000, 109414)   = 0 
socket(PF_NETLINK, SOCK_RAW, 0)   = 3 
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [32768], 4) = 0 
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [1048576], 4) = 0 
bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0 
getsockname(3, {sa_family=AF_NETLINK, pid=6804, groups=00000000}, [12]) = 0 
sendto(3, "\24\0\0\0\22\0\1\3\214;\367P\0\0\0\0\0\0\0\0", 20, 0, NULL, 0) = 20 
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\344\3\0\0\20\0\2\0\214;\367P\224\32\0\0\0\0\4\3\1\0\0\0I\0\1\0\0\0\0\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 2000 
brk(0)         = 0x1bab000 
brk(0x1bcc000)       = 0x1bcc000 
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\24\0\0\0\3\0\2\0\214;\367P\224\32\0\0\0\0\0\0\1\0\0\0I\0\1\0\0\0\0\0"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 20 
sendmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"(\0\0\0\24\0\5\6\215;\367P\0\0\0\0\2 \0\0\1\0\0\0\10\0\2\0\1\2\3\4"..., 40}], msg_controllen=0, msg_flags=0}, 0) = 40 
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"$\0\0\0\2\0\0\0\215;\367P\224\32\0\0\0\0\0\0(\0\0\0\24\0\5\6\215;\367P"..., 16384}], msg_controllen=0, msg_flags=0}, 0) = 36 
exit_group(0)       = ? 
+1

Pourquoi Ne pas "stracer ifconfig paramètres pertinents" pour voir ce que fait ifconfig pour les ajouter. Ou regardez la source de ifconfig, peut-être? –

+0

Il semble qu'il n'utilise pas du tout l'ioctl à cette fin ... hmm – Amir

+1

Vous pourriez vouloir inspecter les sources de 'ip' ici: http://git.kernel.org/?p=linux/kernel/ git/shemminger/iproute2.git; a = arbre; f = ip et allez aussi lire ici: http://www.linuxfoundation.org/collaborate/workgroups/networking/netlink – alk

Répondre

4

Avec l'aide du projet avahi. Voici le code:

$ cat netlink-test.cc

#include <stdlib.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <asm/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <linux/netlink.h> 
#include <linux/rtnetlink.h> 
#include <malloc.h> 
#include <string.h> 
#include <iostream> 

using namespace std; 

struct rtnl_handle 
{ 
    int fd; 
    struct sockaddr_nl local; 
    struct sockaddr_nl peer; 
    __u32 seq; 
    __u32 dump; 
}; 

typedef struct 
{ 
    __u8 family; 
    __u8 bytelen; 
    __s16 bitlen; 
    __u32 flags; 
    __u32 data[8]; 
} inet_prefix; 

/* This uses a non-standard parsing (ie not inet_aton, or inet_pton) 
* because of legacy choice to parse 10.8 as 10.8.0.0 not 10.0.0.8 
*/ 
static int get_addr_ipv4(__u8 *ap, const char *cp) 
{ 
    int i; 

    for (i = 0; i < 4; i++) { 
     unsigned long n; 
     char *endp; 

     n = strtoul(cp, &endp, 0); 
     if (n > 255) 
      return -1;  /* bogus network value */ 

     if (endp == cp) /* no digits */ 
      return -1; 

     ap[i] = n; 

     if (*endp == '\0') 
      break; 

     if (i == 3 || *endp != '.') 
      return -1;  /* extra characters */ 
     cp = endp + 1; 
    } 

    return 1; 
} 

// This function is to open the netlink socket as the name suggests. 
int netlink_open(struct rtnl_handle* rth) 
{ 
    int addr_len; 
    memset(rth, 0, sizeof(rth)); 

    // Creating the netlink socket of family NETLINK_ROUTE 

    rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 
    if (rth->fd < 0) 
    { 
     perror("cannot open netlink socket"); 
     return -1; 
    } 
    memset(&rth->local, 0, sizeof(rth->local)); 
    rth->local.nl_family = AF_NETLINK; 
    rth->local.nl_groups = 0; 

    // Binding the netlink socket 
    if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) 
    { 
     perror("cannot bind netlink socket"); 
     return -1; 
    } 
    addr_len = sizeof(rth->local); 
    if (getsockname(rth->fd, (struct sockaddr*)&rth->local, (socklen_t*) &addr_len) < 0) 
    { 
     perror("cannot getsockname"); 
     return -1; 
    } 
    if (addr_len != sizeof(rth->local)) 
    { 
     fprintf(stderr, "wrong address lenght %d\n", addr_len); 
     return -1; 
    } 
    if (rth->local.nl_family != AF_NETLINK) 
    { 
     fprintf(stderr, "wrong address family %d\n", rth->local.nl_family); 
     return -1; 
    } 
    rth->seq = time(NULL); 
    return 0; 
} 

// This function does the actual reading and writing to the netlink socket 
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, 
     unsigned groups, struct nlmsghdr *answer) 
{ 
    int status; 
    struct nlmsghdr *h; 
    struct sockaddr_nl nladdr; 
    // Forming the iovector with the netlink packet. 
    struct iovec iov = { (void*)n, n->nlmsg_len }; 
    char buf[8192]; 
    // Forming the message to be sent. 
    struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; 
    // Filling up the details of the netlink socket to be contacted in the 
    // kernel. 
    memset(&nladdr, 0, sizeof(nladdr)); 
    nladdr.nl_family = AF_NETLINK; 
    nladdr.nl_pid = peer; 
    nladdr.nl_groups = groups; 
    n->nlmsg_seq = ++rtnl->seq; 
    if (answer == NULL) 
     n->nlmsg_flags |= NLM_F_ACK; 
    // Actual sending of the message, status contains success/failure 
    status = sendmsg(rtnl->fd, &msg, 0); 
    if (status < 0) 
     return -1; 
} 




// This is the utility function for adding the parameters to the packet. 
int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) 
{ 
    int len = RTA_LENGTH(alen); 
    struct rtattr *rta; 

    if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) 
     return -1; 
    rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); 
    rta->rta_type = type; 
    rta->rta_len = len; 
    memcpy(RTA_DATA(rta), data, alen); 
    n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; 
    return 0; 
} 


int get_addr_1(inet_prefix *addr, const char *name, int family) 
{ 
    memset(addr, 0, sizeof(*addr)); 

    if (strcmp(name, "default") == 0 || 
      strcmp(name, "all") == 0 || 
      strcmp(name, "any") == 0) { 
     if (family == AF_DECnet) 
      return -1; 
     addr->family = family; 
     addr->bytelen = (family == AF_INET6 ? 16 : 4); 
     addr->bitlen = -1; 
     return 0; 
    } 

    if (strchr(name, ':')) { 
     addr->family = AF_INET6; 
     if (family != AF_UNSPEC && family != AF_INET6) 
      return -1; 
     if (inet_pton(AF_INET6, name, addr->data) <= 0) 
      return -1; 
     addr->bytelen = 16; 
     addr->bitlen = -1; 
     return 0; 
    } 


    addr->family = AF_INET; 
    if (family != AF_UNSPEC && family != AF_INET) 
     return -1; 

    if (get_addr_ipv4((__u8 *)addr->data, name) <= 0) 
     return -1; 

    addr->bytelen = 4; 
    addr->bitlen = -1; 
    return 0; 
} 

int get_prefix(inet_prefix *dst, char *arg, int family) 
{ 
    int err; 
    unsigned plen; 

    memset(dst, 0, sizeof(*dst)); 

    if (strcmp(arg, "default") == 0 || 
      strcmp(arg, "any") == 0 || 
      strcmp(arg, "all") == 0) { 
     if (family == AF_DECnet) 
      return -1; 
     dst->family = family; 
     dst->bytelen = 0; 
     dst->bitlen = 0; 
     return 0; 
    } 

    err = get_addr_1(dst, arg, family); 
    if (err == 0) { 
     switch(dst->family) { 
      case AF_INET6: 
       dst->bitlen = 128; 
       break; 
      case AF_DECnet: 
       dst->bitlen = 16; 
       break; 
      default: 
      case AF_INET: 
       dst->bitlen = 32; 
     } 
    } 
    return err; 
} 


int add_IP_Address(char * IP, struct rtnl_handle * rth) 
{ 

    inet_prefix lcl; 
    // structure of the netlink packet. 
    struct { 
     struct nlmsghdr  n; 
     struct ifaddrmsg ifa; 
     char   buf[1024]; 
    } req; 

    memset(&req, 0, sizeof(req)); 
    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); 
    req.n.nlmsg_type = RTM_NEWADDR; 
    req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST; 


// req.n.nlmsg_type = RTM_DELADDR; 
// req.n.nlmsg_flags = NLM_F_REQUEST; 

    req.ifa.ifa_family = AF_INET ; 
    req.ifa.ifa_prefixlen = 32 ; 
    req.ifa.ifa_index = 1 ; // get the loopback index 
    req.ifa.ifa_scope = 0 ; 

    get_prefix(&lcl, IP, req.ifa.ifa_family); 
    if (req.ifa.ifa_family == AF_UNSPEC) 
     req.ifa.ifa_family = lcl.family; 
    addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); 

    if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) 
     return -2; 
} 

int main(int argc, char **argv) 
{ 
    struct rtnl_handle * rth; 
    netlink_open(rth); 
    char * ip = "1.2.3.4"; 
    return add_IP_Address(ip,rth); 
} 

Pour la suppression, il vous suffit de décommenter:

req.n.nlmsg_type = RTM_DELADDR; 
    req.n.nlmsg_flags = NLM_F_REQUEST; 

et commentaires:

req.n.nlmsg_type = RTM_NEWADDR; 
    req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST; 
2

D'abord, cette réponse est seulement pour Linux. La configuration réseau/interface/routage n'est définie dans aucune norme, de sorte que chaque système d'exploitation implémente sa propre façon de configurer le réseau. Dans Linux, la configuration réseau est effectuée via des sockets NETLINK (pas ioctl, peut-être dans d'autres systèmes d'exploitation que je ne connais pas), qui sont une famille de sockets spéciale pour communiquer le noyau et l'utilisateur. Pour être plus précis, il est configuré par le protocole NETLINK_ROUTE sur une socket NETLINK. Dans le strace que vous pouvez voir des affiches vous comment il a créé la prise NETLIK:

socket(PF_NETLINK, SOCK_RAW, 0)   = 3 

Et le

sendto(3, "\24\0\0\0\22\0\1\3\214;\367P\0\0\0\0\0\0\0\0", 20, 0, NULL, 0) = 20 

Je suis sûr que c'est une demande NETLINK_ROUTE avec un message RTM_NEWADDR. Le reste de la ligne peut être interprété comme une communication de message de protocole NETLINK_ROUTE.

Vous pouvez en apprendre davantage sur NETLINK_ROUTE here, et trouver des exemples here et Here, et comme @alk a reccommended, la lecture ip source pourrait être quelque chose d'intéressant de savoir ce qui est exactement happenning.

Questions connexes