Cách đặt địa chỉ IP từ chương trình C trong Linux?

Cách đặt địa chỉ IP từ chương trình C trong Linux?

Chia sẻ kiến thức 04/12/2021

Sử dụng lệnh strace và ifconfig tôi có thể đặt được IP, tuy nhiên nó khá rối và không hoàn chỉnh. Có cách nào để đặt địa chỉ IP từ chương trình C trong Linux mà nó đơn giản, hoàn chỉnh hơn không?

Bằng cách sử dụng lệnh strace và ifconfig, tôi thấy rằng tôi có thể đặt địa chỉ IP theo cách dưới đây. Tuy nhiên, tôi không hài lòng với giải pháp này: “inet_pton(AF_INET, “10.12.0.1”, ifr.ifr_addr.sa_data + 2);”. Làm cách nào để đặt địa chỉ IP từ chương trình C trong Linux?

1. Kết quả cài đặt địa chỉ IP của tôi

Đặt địa chỉ IP máy tính từ chương trình C

#include <sys/ioctl.h>

#include <arpa/inet.h>

#include <net/if.h>

#include <string.h>

int main(int argc, const char *argv[]) {

    struct ifreq ifr;

    const char * name = “eth1”;

    int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);

    strncpy(ifr.ifr_name, name, IFNAMSIZ);

    ifr.ifr_addr.sa_family = AF_INET;

    inet_pton(AF_INET, “10.12.0.1”, ifr.ifr_addr.sa_data + 2);

    ioctl(fd, SIOCSIFADDR, &ifr);

    inet_pton(AF_INET, “255.255.0.0”, ifr.ifr_addr.sa_data + 2);

    ioctl(fd, SIOCSIFNETMASK, &ifr);

    ioctl(fd, SIOCGIFFLAGS, &ifr);

    strncpy(ifr.ifr_name, name, IFNAMSIZ);

    ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);

    ioctl(fd, SIOCSIFFLAGS, &ifr);

    return 0;

}

2. Hỗ trợ giải pháp cài đặt địa chỉ IP từ chương trình C trong Linux

2.1. Phương pháp cài đặt địa chỉ IP từ chương trình C trong Linux 1

Đặt địa chỉ IP máy tính từ chương trình C

Để cài đặt địa chỉ IP từ chương trình C trong Linux, bạn có thể thử nghiệm cách này. 

Cách “đúng” cho IPv4 mà không cần phép thuật +2:

struct sockaddr_in* addr = (struct sockaddr_in*)&ifr.ifr_addr;

inet_pton(AF_INET, “10.12.0.1”, &addr->sin_addr);

Để sử dụng IPv6, hãy truyền nó tới sockaddr_in6

2.2. Phương pháp cài đặt địa chỉ IP từ chương trình C trong Linux 2

Tạo ra một bản sao của chương trình “ip” iproute2 (in / sbin / ip) với các tham số liên quan.

Giao diện ioctl nói chung là lỗi thời và không cho phép bạn định cấu hình tất cả các tham số (ví dụ: bí danh IP chưa được đặt tên).

Ngay cả những daemon như dhcpcd cần thay đổi địa chỉ IP, thường làm điều đó bằng cách tạo ra một chương trình bên ngoài… nó không giống như bạn sẽ làm điều đó thường xuyên.

=> Xem thêm: Tạo mã chung với cài đặt Macro trong C

2.3. Phương pháp cài đặt địa chỉ IP từ chương trình C trong Linux 3

Sử dụng:

set_ip(“eth0”, “192.168.181.128”, “192.168.181.1”);

Quá trình và kết quả cài đặt địa chỉ IP từ chương trình C trong Linux như sau:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>           // close()

#include <string.h>           // strcpy, memset(), and memcpy()

#include <netdb.h>            // struct addrinfo

#include <sys/types.h>        // needed for socket(), uint8_t, uint16_t

#include <sys/socket.h>       // needed for socket()

#include <netinet/in.h>       // IPPROTO_RAW, INET_ADDRSTRLEN

#include <netinet/ip.h>       // IP_MAXPACKET (which is 65535)

#include <arpa/inet.h>        // inet_pton() and inet_ntop()

#include <sys/ioctl.h>        // macro ioctl is defined

#include <bits/ioctls.h>      // defines values for argument “request” of ioctl.

#include <net/if.h>           // struct ifreq

#include <linux/if_ether.h>   // ETH_P_ARP = 0x0806

#include <linux/if_packet.h>  // struct sockaddr_ll (see man 7 packet)

#include <net/ethernet.h>

#include <errno.h>            // errno, perror()

#include <netinet/in.h>

#include <net/route.h>    

 /**

    * Create socket function

    */

    int create_socket() {

      int sockfd = 0;

      sockfd = socket(AF_INET, SOCK_DGRAM, 0);

      if(sockfd == -1){

        fprintf(stderr, “Could not get socket.\n”);

        return -1;

      }

      return sockfd;

    }

    /**

    * Generic ioctrlcall to reduce code size

    */

    int generic_ioctrlcall(int sockfd, u_long *flags, struct ifreq *ifr) {

      if (ioctl(sockfd, (long unsigned int)flags, &ifr) < 0) {

        fprintf(stderr, “ioctl: %s\n”, (char *)flags);

        return -1;

      }

      return 1;

    }

    /**

    * Set route with metric 100

    */

    int set_route(int sockfd, char *gateway_addr,  struct sockaddr_in *addr) {

      struct rtentry route;

      int err = 0;

      memset(&route, 0, sizeof(route));

      addr = (struct sockaddr_in*) &route.rt_gateway;

      addr->sin_family = AF_INET;

      addr->sin_addr.s_addr = inet_addr(gateway_addr);

      addr = (struct sockaddr_in*) &route.rt_dst;

      addr->sin_family = AF_INET;

      addr->sin_addr.s_addr = inet_addr(“0.0.0.0”);

      addr = (struct sockaddr_in*) &route.rt_genmask;

      addr->sin_family = AF_INET;

      addr->sin_addr.s_addr = inet_addr(“0.0.0.0”);

      route.rt_flags = RTF_UP | RTF_GATEWAY;

      route.rt_metric = 100;

      err = ioctl(sockfd, SIOCADDRT, &route);

      if ((err) < 0) {

        fprintf(stderr, “ioctl: %s\n”,  “mahdi MOAHMMADI Error”);

        return -1;

      }

      return 1;

    }

    /**

    * Set ip function

    */

    int set_ip(char *iface_name, char *ip_addr, char *gateway_addr)

    {

      if(!iface_name)

        return -1;

      struct ifreq ifr;

      struct sockaddr_in sin;

      int sockfd = create_socket();

      sin.sin_family = AF_INET;

      // Convert IP from numbers and dots to binary notation

      inet_aton(ip_addr,&sin.sin_addr.s_addr);

      /* get interface name */

      strncpy(ifr.ifr_name, iface_name, IFNAMSIZ);

      /* Read interface flags */

      generic_ioctrlcall(sockfd, (u_long *)”SIOCGIFFLAGS”, &ifr);

      /*

      * Expected in <net/if.h> according to

      * “UNIX Network Programming”.

      */

      #ifdef ifr_flags

      # define IRFFLAGS       ifr_flags

      #else   /* Present on kFreeBSD */

      # define IRFFLAGS       ifr_flagshigh

      #endif

      // If interface is down, bring it up

      if (ifr.IRFFLAGS | ~(IFF_UP)) {

        ifr.IRFFLAGS |= IFF_UP;

        generic_ioctrlcall(sockfd, (u_long *)”SIOCSIFFLAGS”, &ifr);

      }

      // Set route

      set_route(sockfd, gateway_addr    ,  &sin);

      memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr)); 

      // Set interface address

      if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {

        fprintf(stderr, “Cannot set IP address. “);

        perror(ifr.ifr_name);

        return -1;

      }             

      #undef IRFFLAGS 

      return 0;

    }

Như vậy, trên Linux bạn hoàn toàn có thể cài đặt địa chỉ IP từ chương trình C cho máy tính của mình. Hãy cẩn trọng khi lựa chọn phương pháp và thực hiện các thao tác, để tránh sai sót, nhầm lẫn. 

Bài gốc: https://stackoverflow.com/questions/6652384/how-to-set-the-ip-address-from-c-in-linux

Nguyễn Vân Anh (Theo Stack Overflow)

ĐĂNG KÝ TƯ VẤN HỌC LẬP TRÌNH TẠI FUNiX

Bình luận (
0
)

Bài liên quan

  • Tầng 0, tòa nhà FPT, 17 Duy Tân, Q. Cầu Giấy, Hà Nội
  • info@funix.edu.vn
  • 0782313602 (Zalo, Viber)        
Chat Button
FUNiX V2 GenAI Chatbot ×

yêu cầu gọi lại