zoukankan      html  css  js  c++  java
  • 在Linux上使用C语言编程获取IPv4地址及子网掩码

    在Linux上(如Ubuntu或CentOS), 获取某个Network Interface比如eth0的IP地址等信息,我们可以使用ifconfig或者ip addr show命令。

    $ ifconfig eth0
    eth0      Link encap:Ethernet  HWaddr 00:25:64:ba:8d:be
              inet addr:192.168.1.102  Bcast:192.168.1.255  Mask:255.255.255.0
              inet6 addr: fe80::225:64ff:feba:8dbe/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:31242 errors:0 dropped:0 overruns:0 frame:0
              TX packets:29415 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000
              RX bytes:29102650 (29.1 MB)  TX bytes:4090669 (4.0 MB)
              Interrupt:16
    
    $ ip addr show eth0
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
        link/ether 00:25:64:ba:8d:be brd ff:ff:ff:ff:ff:ff
        inet 192.168.1.102/24 brd 192.168.1.255 scope global eth0
           valid_lft forever preferred_lft forever
        inet6 fe80::225:64ff:feba:8dbe/64 scope link
           valid_lft forever preferred_lft forever

    那么用C语言编程怎么实现呢? 先用strace工具观察一下ifconfig eth0的运行内幕。

    $ strace ifconfig eth0
    execve("/sbin/ifconfig", ["ifconfig", "eth0"], [/* 71 vars */]) = 0
    brk(0)                                  = 0x9565000
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76fe000
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat64(3, {st_mode=S_IFREG|0644, st_size=114965, ...}) = 0
    mmap2(NULL, 114965, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76e1000
    close(3)                                = 0
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "177ELF111331P2341004"..., 512) = 512
    fstat64(3, {st_mode=S_IFREG|0755, st_size=1763068, ...}) = 0
    mmap2(NULL, 1772156, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7530000
    mmap2(0xb76db000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1aa000) = 0xb76db000
    mmap2(0xb76de000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb76de000
    close(3)                                = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb752f000
    set_thread_area({entry_number:-1 -> 6, base_addr:0xb752f940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
    mprotect(0xb76db000, 8192, PROT_READ)   = 0
    mprotect(0x8058000, 4096, PROT_READ)    = 0
    mprotect(0xb7724000, 4096, PROT_READ)   = 0
    munmap(0xb76e1000, 114965)              = 0
    brk(0)                                  = 0x9565000
    brk(0x9586000)                          = 0x9586000
    open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
    fstat64(3, {st_mode=S_IFREG|0644, st_size=8752496, ...}) = 0
    mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb732f000
    mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0x855000) = 0xb76fd000
    close(3)                                = 0
    uname({sys="Linux", node="idorax", ...}) = 0
    access("/proc/net", R_OK)               = 0
    access("/proc/net/unix", R_OK)          = 0
    socket(PF_LOCAL, SOCK_DGRAM, 0)         = 3
    socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
    access("/proc/net/if_inet6", R_OK)      = 0
    socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
    access("/proc/net/ax25", R_OK)          = -1 ENOENT (No such file or directory)
    access("/proc/net/nr", R_OK)            = -1 ENOENT (No such file or directory)
    access("/proc/net/rose", R_OK)          = -1 ENOENT (No such file or directory)
    access("/proc/net/ipx", R_OK)           = -1 ENOENT (No such file or directory)
    access("/proc/net/appletalk", R_OK)     = -1 ENOENT (No such file or directory)
    access("/proc/sys/net/econet", R_OK)    = -1 ENOENT (No such file or directory)
    access("/proc/sys/net/ash", R_OK)       = -1 ENOENT (No such file or directory)
    access("/proc/net/x25", R_OK)           = -1 ENOENT (No such file or directory)
    open("/proc/net/dev", O_RDONLY)         = 6
    fstat64(6, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76fc000
    read(6, "Inter-|   Receive               "..., 1024) = 447
    close(6)                                = 0
    munmap(0xb76fc000, 4096)                = 0
    ioctl(5, SIOCGIFFLAGS, {ifr_name="eth0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
    ioctl(5, SIOCGIFHWADDR, {ifr_name="eth0", ifr_hwaddr=00:25:64:ba:8d:be}) = 0
    ioctl(5, SIOCGIFMETRIC, {ifr_name="eth0", ifr_metric=0}) = 0
    ioctl(5, SIOCGIFMTU, {ifr_name="eth0", ifr_mtu=1500}) = 0
    ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=16, dma=0, port=0}}) = 0
    ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=16, dma=0, port=0}}) = 0
    ioctl(5, SIOCGIFTXQLEN, {ifr_name="eth0", ifr_qlen=1000}) = 0
    open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 6
    fstat64(6, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76fc000
    read(6, "# Locale name alias data base.
    #"..., 4096) = 2570
    read(6, "", 4096)                       = 0
    close(6)                                = 0
    munmap(0xb76fc000, 4096)                = 0
    open("/usr/share/locale/en_US/LC_MESSAGES/net-tools.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
    open("/usr/share/locale/en/LC_MESSAGES/net-tools.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
    open("/usr/share/locale-langpack/en_US/LC_MESSAGES/net-tools.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
    open("/usr/share/locale-langpack/en/LC_MESSAGES/net-tools.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
    ioctl(4, SIOCGIFADDR, {ifr_name="eth0", ifr_addr={AF_INET, inet_addr("192.168.1.102")}}) = 0
    ioctl(4, SIOCGIFDSTADDR, {ifr_name="eth0", ifr_dstaddr={AF_INET, inet_addr("192.168.1.102")}}) = 0
    ioctl(4, SIOCGIFBRDADDR, {ifr_name="eth0", ifr_broadaddr={AF_INET, inet_addr("192.168.1.255")}}) = 0
    ioctl(4, SIOCGIFNETMASK, {ifr_name="eth0", ifr_netmask={AF_INET, inet_addr("255.255.255.0")}}) = 0
    fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 6), ...}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76fc000
    write(1, "eth0      Link encap:Ethernet  H"..., 58eth0      Link encap:Ethernet  HWaddr 00:25:64:ba:8d:be
    ) = 58
    write(1, "          inet addr:192.168.1.10"..., 75          inet addr:192.168.1.102  Bcast:192.168.1.255  Mask:255.255.255.0
    ) = 75
    open("/proc/net/if_inet6", O_RDONLY)    = 6
    fstat64(6, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76fb000
    read(6, "00000000000000000000000000000001"..., 1024) = 108
    read(6, "", 1024)                       = 0
    write(1, "          inet6 addr: fe80::225:"..., 61          inet6 addr: fe80::225:64ff:feba:8dbe/64 Scope:Link
    ) = 61
    read(6, "", 1024)                       = 0
    close(6)                                = 0
    munmap(0xb76fb000, 4096)                = 0
    write(1, "          UP BROADCAST RUNNING M"..., 61          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
    ) = 61
    write(1, "          RX packets:31318 error"..., 65          RX packets:31318 errors:0 dropped:0 overruns:0 frame:0
    ) = 65
    write(1, "          TX packets:29503 error"..., 67          TX packets:29503 errors:0 dropped:0 overruns:0 carrier:0
    ) = 67
    write(1, "          collisions:0 txqueuele"..., 40          collisions:0 txqueuelen:1000
    ) = 40
    write(1, "          RX bytes:29127563 (29."..., 65          RX bytes:29127563 (29.1 MB)  TX bytes:4104503 (4.1 MB)
    ) = 65
    write(1, "          Interrupt:16 
    ", 24          Interrupt:16
    ) = 24
    write(1, "
    ", 1
    )                       = 1
    close(5)                                = 0
    exit_group(0)                           = ?
    +++ exited with 0 +++

    注意上面的socket()和ioctl(), 我们不难发现如下关键调用,

    socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
    
    ioctl(4, SIOCGIFADDR, {ifr_name="eth0", ifr_addr={AF_INET, inet_addr("192.168.1.102")}}) = 0
    ioctl(4, SIOCGIFNETMASK, {ifr_name="eth0", ifr_netmask={AF_INET, inet_addr("255.255.255.0")}}) = 0

    好了,现在可以上C代码了,(foo_get.c)

     1 /**
     2  * get IPv4 address and subnet mask of a network interface
     3  */
     4 #include <stdio.h>
     5 #include <unistd.h>
     6 #include <string.h>
     7 #include <sys/socket.h>
     8 #include <sys/ioctl.h>
     9 #include <net/if.h>
    10 #include <arpa/inet.h>
    11 
    12 int
    13 main(int argc, char *argv[])
    14 {
    15         int rc = 0;
    16         struct sockaddr_in *addr = NULL;
    17 
    18         if (argc != 2) {
    19                 fprintf(stderr, "Usage: %s <ifname>
    ", argv[0]);
    20                 return -1;
    21         }
    22 
    23         char *ifname = argv[1];
    24 
    25         struct ifreq ifr;
    26         memset(&ifr, 0, sizeof(struct ifreq));
    27 
    28         /* 0. create a socket */
    29         int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    30         if (fd == -1)
    31                 return -1;
    32 
    33         /* 1. set type of address to retrieve : IPv4 */
    34         ifr.ifr_addr.sa_family = AF_INET;
    35 
    36         /* 2. copy interface name to ifreq structure */
    37         strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
    38 
    39         /* 3. get the IP address */
    40         if ((rc = ioctl(fd, SIOCGIFADDR, &ifr)) != 0)
    41                 goto done;
    42 
    43         char ipv4[16] = { 0 };
    44         addr = (struct sockaddr_in *)&ifr.ifr_addr;
    45         strncpy(ipv4, inet_ntoa(addr->sin_addr), sizeof(ipv4));
    46 
    47         /* 4. get the mask */
    48         if ((rc = ioctl(fd, SIOCGIFNETMASK, &ifr)) != 0)
    49                 goto done;
    50 
    51         char mask[16] = { 0 };
    52         addr = (struct sockaddr_in *)&ifr.ifr_addr;
    53         strncpy(mask, inet_ntoa(addr->sin_addr), sizeof(mask));
    54 
    55         /* 5. display */
    56         printf("IFNAME:IPv4:MASK
    ");
    57         printf("%s:%s:%s
    ", ifname, ipv4, mask);
    58 
    59         /* 6. close the socket */
    60 done:
    61         close(fd);
    62 
    63         return rc;
    64 }

    编译并测试,

    $ gcc -g -Wall -std=gnu99 -o foo_get foo_get.c
    
    $ ./foo_get eth0
    IFNAME:IPv4:MASK
    eth0:192.168.1.102:255.255.255.0
    
    $ ./foo_get lo
    IFNAME:IPv4:MASK
    lo:127.0.0.1:255.0.0.0

    参考资料:

    • NETDEVICE(7)
    • INET(3)
    • https://stackoverflow.com/questions/6652384/how-to-set-the-ip-address-from-c-in-linux
  • 相关阅读:
    java多线程--定时器Timer的使用
    java多线程--线程池的使用
    java多线程--多线程基础小结
    java基础--java.util.Date类型小结
    onClickRow 事件
    C#里的SubString和Convert.ToDateTime
    jquery+easyui开发、培训文档
    Jquery函数大全
    前端最全的 API 集锦
    17个CSS知识点整理
  • 原文地址:https://www.cnblogs.com/idorax/p/7329276.html
Copyright © 2011-2022 走看看