如何在 Linux 中用 C 语言设置 IP 地址
- 2024-11-08 09:04:00
- admin 原创
- 68
问题描述:
通过使用strace
和ifconfig
,我发现可以通过这种方式设置 IP 地址:
#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;
}
但我对这个解决方案不太满意:
inet_pton(AF_INET, "10.12.0.1", ifr.ifr_addr.sa_data + 2);
做这件事的“正确”方法是什么?
解决方案 1:
不使用 magic +2 的 IPv4 的“正确”方法:
struct sockaddr_in* addr = (struct sockaddr_in*)&ifr.ifr_addr;
inet_pton(AF_INET, "10.12.0.1", &addr->sin_addr);
要使用 IPv6,将其转换为sockaddr_in6
解决方案 2:
#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.
");
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
", (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
", "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;
}
用法:
set_ip("eth0", "192.168.181.128", "192.168.181.1");
解决方案 3:
正确的做法是生成一个 iproute2 “ip” 程序的副本(在 /sbin/ip 中),并附带相关参数。
ioctl 接口通常已经过时,并且不允许您配置所有参数(例如,未命名的 IP 别名)。
即使像 dhcpcd 这样需要更改 IP 地址的守护进程,通常也是通过生成外部程序来实现的……你不会经常这样做。
解决方案 4:
您好:在 set_ip 函数中,它给出了一个错误。我必须从以下位置进行更改:
inet_aton(ip_addr,&sin.sin_addr.s_addr);
到
inet_aton(ip_addr,&sin.sin_addr);
并且效果很好。
相关推荐
热门文章
项目管理软件有哪些?
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
热门标签
云禅道AD