Linux c language to obtain the local ip, subnet mask

Article directory

  • 1. Obtain the local ip
    • 1.1 Get the ip of the specified network card
    • 1.2 Obtain the ip address of all network interfaces of this machine
  • 2. Obtain the local subnet mask
  • 3. Obtain network interface information

1. Get local ip

1.1 Get the ip of the specified network card

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>

int main(int argc, char *argv[]) {<!-- -->

    if(argc < 2){<!-- -->
        printf("please input correct , argc = %d\
", argc);
        return -1;
    }

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {<!-- -->
        perror("socket() error");
        return -1;
    }

    const char *network_card_name = argv[1];

    struct ifreq ifr;
    memset( &ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, network_card_name, IFNAMSIZ - 1);

    if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) {<!-- -->
        perror("ioctl() error");
        close(sockfd);
        return -1;
    }

    struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
    char ip_address[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, & sin->sin_addr, ip_address, sizeof(ip_address));

    printf("IP Address: %s\
", ip_address);

    close(sockfd);
    return 0;
}

The ifconfig command queries the name of the network interface of the machine, and then adds the input parameter when running the program: the name of the network interface.

./a.out network_card_name

Use the ioctl() function to get the IP address of the machine. This method obtains the IP address of the machine by querying the IP address of the specified network interface.

(1) Create a socket based on IP protocol.

A socket is created using the socket() system call. The first parameter of the socket() system call specifies the address family of the socket, here specifying AF_INET means using an IPv4 address. The second parameter specifies the type of socket, here specified as SOCK_DGRAM means to use the datagram (Datagram) transmission method. The third parameter can be used to specify the protocol type, here it is set to 0, which means to use the default protocol.

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {<!-- -->
    perror("socket() error");
    return -1;
}

(2) Prepare an ifreq structure to save the information of the network interface.

 struct ifreq ifr;
  memset( &ifr, 0, sizeof(ifr));
  strncpy(ifr.ifr_name, network_card_name, IFNAMSIZ - 1);

struct ifreq is a structure used to store network interface information, defined in net/if.h in Linux, and its definition is as follows:

/* Interface request structure used for socket ioctl's. All interface
   ioctl's must have parameter definitions which begin with ifr_name.
   The remainder may be interface specific. */

struct ifreq
  {<!-- -->
#define IFHWADDRLEN 6
#define IFNAMSIZ IF_NAMESIZE
    union
      {<!-- -->
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
      } ifr_ifrn;

    union
      {<!-- -->
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short int ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
__caddr_t ifru_data;
      } ifr_ifru;
  };

Among them, ifrn_name saves the name of the network interface, ifru_addr saves the IP address of the network interface, ifru_hwaddr saves the MAC address of the network interface, and ifru_flags saves the status flag of the network interface, etc. In fact, members of struct ifreq ifru_addr, ifru_dstaddr, ifru_broadaddr, ifru_netmask, ifru_hwaddr, etc. are variants of the sockaddr structure, which can store different types of address information.

When using the ioctl() function to query network interface information, we can save the name of the network interface to be queried in ifrn_name, and then pass the struct ifreq structure to the kernel as a parameter of the ioctl() function, and the kernel will save the query result in Ifru_addr, ifru_hwaddr and other members. We can extract corresponding address information from corresponding members according to actual needs.

It should be noted that since ifru_addr, ifru_dstaddr, ifru_broadaddr, ifru_netmask, ifru_hwaddr and other members are variants of the sockaddr structure, it is necessary to select the appropriate member according to the actual situation when using it to avoid type errors.

(3) Call the ioctl() function to query the IP address of the network interface.

 if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) {<!-- -->
     perror("ioctl() error");
     close(sockfd);
     return -1;
 }

In Linux, the network interface information is stored in the kernel, and the information of the network interface can be queried and set through the ioctl() system call. The ioctl() system call provides a general interface that can be used to query and set the information of various devices, including network interfaces, hard disks, serial ports, etc.

For network interfaces, the ioctl() function is mainly used to query and set the following information:

IP address, subnet mask, broadcast address, MAC address, etc. of the network interface;
The status of the network interface, such as whether it is enabled, whether it is in promiscuous mode, etc.;
The MTU (Maximum Transmission Unit) of the network interface, etc.
When using the ioctl() function to query network interface information, you need to use the struct ifreq structure to save the query and setting parameters. This structure contains parameters that need to be queried and set, such as the name of the network interface, IP address, MAC address, etc. When querying, we can save the name of the network interface to be queried in the ifreq structure, and then pass the structure to the kernel as a parameter of the ioctl() function, and the kernel will save the query result in the corresponding member, such as ifr_addr , ifr_hwaddr and other members. We can extract corresponding address information from corresponding members according to actual needs.

It should be noted that since the address types of network interfaces may be different, such as IPv4, IPv6 and MAC addresses, etc., when using the struct ifreq structure, it is necessary to select appropriate members according to the actual situation to avoid type errors.

In summary, the ioctl() function provides a general interface that can be used to query and set information about various devices, including network interfaces. When using the ioctl() function to query network interface information, you need to use the struct ifreq structure to save the query and setting parameters, and select appropriate members according to the actual situation to extract the corresponding address information.

(4) Obtain the IP address from the ifr structure and convert it to a string format

 struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
    char ip_address[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, & sin->sin_addr, ip_address, sizeof(ip_address));

struct sockaddr_in:

struct sockaddr_in is a structure used to describe IPv4 address, defined in netinet/in.h in Linux. It is defined as follows:

/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
  {<!-- -->
    in_addr_t s_addr;
  };
/* Structure describing an Internet socket address. */
struct sockaddr_in
  {<!-- -->
    __SOCKADDR_COMMON(sin_);
    in_port_t sin_port; /* Port number. */
    struct in_addr sin_addr; /* Internet address. */

    /* Pad to size of `struct sockaddr'. */
    unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof(in_port_t) -
sizeof(struct in_addr)];
  };

Among them, sin_family is the address family, and it is fixed as AF_INET to represent the IPv4 address family. sin_port is the port number that identifies the port of the network connection. sin_addr is a structure used to save IPv4 address. sin_zero is an array to pad the size of the struct so that struct sockaddr_in and struct sockaddr are the same size.

It should be noted that the struct in_addr structure is an alias of the unsigned long type and is used to store IPv4 addresses. An IPv4 address is a 32-bit binary number, usually expressed in dotted decimal notation.

In short, the struct sockaddr_in structure is a structure used to describe IPv4 addresses, including address family, port number, IPv4 address and other members, and has the same size as struct sockaddr. When using socket programming, we can use the struct sockaddr_in structure to represent the IPv4 address.

inet_ntop function:

/* Convert a Internet address in binary network format for interface
   type AF in buffer starting at CP to presentation form and place
   result in buffer of length LEN starting at BUF. */
extern const char *inet_ntop (int __af, const void *__restrict __cp,
char *__restrict __buf, socklen_t __len)
     __THROW;

This is the function prototype of the inet_ntop() function, defined in the arpa/inet.h header file. This function is used to convert a binary IP address in network byte order into a dotted decimal string representation.

In the function prototype, the __af parameter indicates the address family, which can be AF_INET or AF_INET6. The __cp parameter is a pointer to a buffer of binary IP addresses, and the length of the buffer is related to the address family. The __buf parameter is a pointer to the target buffer used to save the converted dotted decimal string representation, and the __len parameter indicates the length of the target buffer.

The return value of the function is a pointer to a character string, which represents the converted IP address. Returns a pointer to the destination buffer if the conversion was successful, or NULL if the conversion failed.

It should be noted that the inet_ntop() function can only convert the binary IP address in network byte order into a dotted decimal string representation. If you need to convert the binary IP address in host byte order into a dotted decimal string means, you need to convert it to network byte order first, and then call the inet_ntop() function.

In short, the inet_ntop() function is used to convert a binary IP address in network byte order into a dotted decimal string representation, and save the result in the destination buffer. This function is often used in socket programming to convert a network address into a readable form.

1.2 Obtain the ip address of all network interfaces of this machine

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>

int main() {<!-- -->
    struct ifaddrs *ifap, *ifa;
    struct sockaddr_in *sa;
    char ip_address[INET_ADDRSTRLEN];

    if (getifaddrs( &ifap) == -1) {<!-- -->
        perror("getifaddrs() error");
        return -1;
    }

    for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {<!-- -->
        if (ifa->ifa_addr != NULL & amp; & amp; ifa->ifa_addr->sa_family == AF_INET) {<!-- -->
            sa = (struct sockaddr_in *) ifa->ifa_addr;
            inet_ntop(AF_INET, &sa->sin_addr, ip_address, sizeof(ip_address));
            printf("%s: %s\
", ifa->ifa_name, ip_address);
        }
    }

    freeifaddrs(ifap);
    return 0;
}

Use the getifaddrs() function to query the IP addresses of all network interfaces in the system.

The program first calls the getifaddrs() function to obtain the information of all network interfaces in the system, and then traverses the linked list to process the address information of each network interface. For an IPv4 address, the program converts it to a dotted decimal string and prints out the name and IP address of the network interface.

Finally, the program frees the memory by calling the freeifaddrs() function, and returns 0.

It should be noted that the getifaddrs() function will return a linked list after the query is successful, and each node in the linked list saves the information of a network interface, including the name of the network interface, IP address, MAC address, etc. When traversing the linked list, it is necessary to judge the address type in each node in order to correctly extract the IP address.

(1)
The getifaddrs() function is a function used to obtain information about all network interfaces on a host.

man getifaddrs
NAME
       getifaddrs, freeifaddrs-get interface addresses

SYNOPSIS
       #include <sys/types.h>
       #include <ifaddrs.h>

       int getifaddrs(struct ifaddrs **ifap);
       void freeifaddrs(struct ifaddrs *ifa);

Among them, ifap is a pointer to a pointer, which is used to return a pointer to a linked list of struct ifaddrs structures. This structure contains information related to the network interface, such as interface name, IPv4/IPv6 address, netmask, MAC address, etc.

The getifaddrs() function returns 0 for success, -1 for failure, and sets the corresponding errno value. If successful, the function will return a pointer to the linked list of the struct ifaddrs structure, and the memory occupied by the linked list of the structure needs to be released using the freeifaddrs() function.

It should be noted that the linked list returned by the getifaddrs() function contains information about all network interfaces on the host, including interfaces that are not enabled, so it is necessary to traverse the entire linked list and check the status and properties of each interface.

In short, the getifaddrs() function is a function used to obtain the information of all network interfaces on the host, and the information of each interface can be obtained by traversing the returned struct ifaddrs structure linked list. In socket programming, this function is often used to obtain the network information of the machine and the properties related to the network interface.

(2)
struct ifaddrs is a structure used to store network interface information, defined in ifaddrs.h in Linux. It is defined as follows:

/* The `getifaddrs' function generates a linked list of these structures.
   Each element of the list describes one network interface. */
struct ifaddrs
{<!-- -->
  struct ifaddrs *ifa_next; /* Pointer to the next structure. */

  char *ifa_name; /* Name of this network interface. */
  unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */

  struct sockaddr *ifa_addr; /* Network address of this interface. */
  struct sockaddr *ifa_netmask; /* Netmask of this interface. */
  union
  {<!-- -->
    /* At most one of the following two is valid. If the IFF_BROADCAST
       bit is set in `ifa_flags', then `ifa_broadaddr' is valid. If the
       IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.
       It is never the case that both these bits are set at once. */
    struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */
    struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */
  } ifa_ifu;
  /* These very same macros are defined by <net/if.h> for `struct ifaddr'.
     So if they are defined already, the existing definitions will be fine. */
# ifndef ifa_broadaddr
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#endif
# ifndef ifa_dstaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
#endif

  void *ifa_data; /* Address-specific data (may be unused). */
};

Among them, ifa_next is a pointer to the next node in the linked list, ifa_name saves the name of the network interface, and ifa_flags saves the status flag of the network interface, such as whether it is enabled or not, whether it is promiscuous mode, etc. ifa_addr saves the IP address of the network interface, and ifa_netmask saves the subnet mask of the network interface. ifu_broadaddr and ifu_dstaddr hold the broadcast address and destination address of the network interface respectively.

It should be noted that since ifu_broadaddr and ifu_dstaddr are unions, only one member can be saved at the same time, and which member to save depends on the type of network interface. If the network interface is a broadcast type, the ifu_broadaddr member holds the broadcast address; if it is a point-to-point type, the ifu_dstaddr member holds the destination address.

In short, the struct ifaddrs structure is used to save network interface information, including name, status, IP address, subnet mask, broadcast address, and destination address. When using the getifaddrs() function to query the network interface information, the function will return a linked list, each node in the linked list saves the information of a network interface, and is described by the struct ifaddrs structure. We can traverse the linked list and process the address information of each node.

2. Get the local subnet mask

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>

int main(int argc, char *argv[]) {<!-- -->

    if(argc < 2){<!-- -->
        printf("please input correct , argc = %d\
", argc);
        return -1;
    }

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {<!-- -->
        perror("socket() error");
        return -1;
    }

    const char *network_card_name = argv[1];

    struct ifreq ifr;
    memset( &ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, network_card_name, IFNAMSIZ - 1);

    if (ioctl(sockfd, SIOCGIFNETMASK, &ifr) < 0) {<!-- -->
        perror("ioctl() error");
        close(sockfd);
        return -1;
    }

    struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_netmask;
    char netmask[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &sin->sin_addr, netmask, sizeof(netmask));

    printf("Netmask: %s\
", netmask);

    close(sockfd);
    return 0;
}

Same as the 1.1 scheme, it is not described here.

3. Get network interface information

The above examples illustrate several schemes for obtaining network interface information. The following describes some common schemes for obtaining network interface information under Linux.
In Linux, there are several common solutions for obtaining network interface information:

(1) getifaddrs() function: This is a standard POSIX function that can be used to obtain network interface information on the system. It returns a linked list pointing to the struct ifaddrs structure, which contains information about each network interface, such as interface name, IP address, mask, and MAC address.

(2) ioctl() function: This is a general I/O control system call, and the network interface information can be obtained by using the SIOCGIFCONF command. This command returns a struct ifconf structure, which contains an array of multiple struct ifreq structures, and each struct ifreq structure contains information about a network interface, such as interface name, IP address, mask, and MAC address.

(3) sysfs file system: In Linux, each network interface corresponds to a sysfs directory, which contains some attribute information of the interface, such as interface name, MAC address, speed, status, etc. Network interface information can be obtained by looking up the corresponding directory in the sysfs file system and reading the corresponding file. For example, the sysfs directory for interface eth0 is /sys/class/net/eth0, which contains a file named address, whose content is the MAC address of the interface.

(4) netlink socket: netlink is a mechanism for communication between the kernel and user space, you can use netlink socket to obtain network interface information. In Linux, network interface information can be obtained through the RTM_GETLINK command of the NETLINK_ROUTE protocol, which returns a struct ifinfomsg structure, which contains attribute information of the network interface, such as interface name, MAC address, status, speed, etc.

These solutions have their own advantages and disadvantages, and the choice of a solution needs to be based on specific needs and application scenarios. For example, getifaddrs() is a high-level API that is easy to use and provides a lot of information, while ioctl() provides finer control and can obtain information that getifaddrs() cannot. The sysfs filesystem and netlink sockets provide more detail, but can be more complicated to use.