之前根据项目要求,需要通过web对linux终端配置IP地址,一种是通过修改脚本文件方式,另一种是通过编程方式。由于采用的嵌入式web服务器中需要实现C代码读取IP地址,所有采用第二中方式。参考了各大神的总结,现将我测试的代码作以记录。
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <error.h>
#include <net/route.h>
#include <unistd.h>
#define MAX_INTERFACE (16)
/**
* @brief 模仿ifconfig打印所有网卡信息.
* @param None.
* @retval None.
* @notes None.
*/
int GetIfAllAddr(void)
{
int fd;
struct ifreq buf[MAX_INTERFACE];
struct ifconf ifc;
int ret = 0;
int if_num = 0;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0)
{
perror(" socket error");
return fd;
}
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = (caddr_t)buf;
ret = ioctl(fd, SIOCGIFCONF, (char *)&ifc);
if(ret < 0)
{
printf("get if config info failed");
goto error_exit;
}
/* 网口总数 ifc.ifc_len 应该是一个输入参数 */
if_num = ifc.ifc_len/sizeof(struct ifreq);
printf("Interface num is %d\n", if_num);
while(if_num--)
{
printf("【%s】: \n", buf[if_num].ifr_name);
/* 获取第n个网卡信息 */
ret = ioctl(fd, SIOCGIFFLAGS, (char *)&buf[if_num]);
if(ret < 0)
{
continue;
}
/* 获取网口状态 */
//get_net_status(buf[if_num].ifr_flags);
/* 获取当前网卡的IP地址 */
ret = ioctl(fd, SIOCGIFADDR, (char *)&buf[if_num]);
if(ret < 0)
{
continue;
}
printf(" IP: %s\n", inet_ntoa(((struct sockaddr_in *)(&buf[if_num].ifr_addr))->sin_addr));
/* 获取当前网卡的MAC */
ret = ioctl(fd, SIOCGIFHWADDR, (char *)&buf[if_num]);
if(ret < 0)
{
continue;
}
printf(" MAC: %02x:%02x:%02x:%02x:%02x:%02x\n\n",
(uint8_t)buf[if_num].ifr_hwaddr.sa_data[0],
(uint8_t)buf[if_num].ifr_hwaddr.sa_data[1],
(uint8_t)buf[if_num].ifr_hwaddr.sa_data[2],
(uint8_t)buf[if_num].ifr_hwaddr.sa_data[3],
(uint8_t)buf[if_num].ifr_hwaddr.sa_data[4],
(uint8_t)buf[if_num].ifr_hwaddr.sa_data[5]
);
}
error_exit:
close(fd);
return ret;
}
/**
* @brief 模仿ifconfig打印所有网卡信息.
* @param *ethName 网卡名字符
* @retval None.
* @notes None.
*/
int GetIfAddr(const char *ethName)
{
int fd;
int ret = 0;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0)
{
perror(" socket error");
return fd;
}
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ethName);
/* 获取第n个网卡信息 */
ret = ioctl(fd, SIOCGIFFLAGS, (char *)&ifr);
if(ret < 0)
{
perror("ioctl_SIOCGIFFLAGS error");
}
printf("%s", ifr.ifr_name);
/* 获取当前网卡的MAC */
ret = ioctl(fd, SIOCGIFHWADDR, (char *)&ifr);
if(ret < 0)
{
perror("ioctl_SIOCGIFHWADDR error");
}
printf(" HWaddr: %02x:%02x:%02x:%02x:%02x:%02x\n",
(uint8_t)ifr.ifr_hwaddr.sa_data[0],
(uint8_t)ifr.ifr_hwaddr.sa_data[1],
(uint8_t)ifr.ifr_hwaddr.sa_data[2],
(uint8_t)ifr.ifr_hwaddr.sa_data[3],
(uint8_t)ifr.ifr_hwaddr.sa_data[4],
(uint8_t)ifr.ifr_hwaddr.sa_data[5]
);
/* 获取当前网卡的IP地址 */
ret = ioctl(fd, SIOCGIFADDR, (char *)&ifr);
if(ret < 0)
{
perror("ioctl_SIOCGIFADDR error");
}
printf(" inet addr:%s ", inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr));
/* 获取当前网卡的广播地址 */
ret = ioctl(fd, SIOCGIFBRDADDR, (char *)&ifr);
if(ret < 0)
{
perror("ioctl_SIOCGIFBRDADDR error");
}
printf("Bcast:%s ", inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr));
/* 获取当前网卡的子网掩码 */
ret = ioctl(fd, SIOCGIFNETMASK, (char *)&ifr);
if(ret < 0)
{
perror("ioctl_SIOCGIFNETMASK error");
}
printf("Mask:%s\n", inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr));
ret = ifr.ifr_flags;
close(fd);
return ret;
}
/**
* @brief 根据网口名称设置IP地址.
* @param *ethName 网卡名字符
* @retval None.
* @notes None.
*/
int SetIfAddr(const char *ethName, char *ipAddr, char *mask, char *gateway)
{
int fd;
int ret = 0;
struct ifreq ifr;
struct sockaddr_in *sin;
struct rtentry rt;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0)
{
perror(" socket error");
return fd;
}
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ethName);
sin = (struct sockaddr_in *)&ifr.ifr_addr;
sin->sin_family = AF_INET;
/* IP地址设置 */
ret = inet_aton(ipAddr, &(sin->sin_addr));
if(ret < 0)
{
perror("inet_aton error");
goto error_exit;
}
ret = ioctl(fd, SIOCSIFADDR, &ifr);
if(ret < 0)
{
perror("ioctl SIOCSIFADDR error");
goto error_exit;
}
/* 子网掩码设置 */
ret = inet_aton(mask, &(sin->sin_addr));
if(ret < 0)
{
perror("inet_aton error");
goto error_exit;
}
ret = ioctl(fd, SIOCSIFNETMASK, &ifr);
if(ret < 0)
{
perror("ioctl SIOCSIFNETMASK error");
goto error_exit;
}
/* 网关 */
memset(&rt, 0, sizeof(struct rtentry));
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = 0;
ret = inet_aton(gateway, &(sin->sin_addr));
if(ret < 0)
{
perror("inet_aton gateway error");
}
memcpy(&rt.rt_gateway, sin, sizeof(struct sockaddr_in));
((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
rt.rt_flags = RTF_GATEWAY;
/* 设置网关,如果所设置的网关与现有网关一样,会报File exists */
ret = ioctl(fd, SIOCADDRT, &rt);
if(ret < 0)
{
perror("ioctl(SIOCADDRT) error in set_default_route\n");
goto error_exit;
}
error_exit:
close(fd);
return ret;
}
int main(int argc, char *argv[])
{
char *ip = "192.168.10.56";
char *mask = "255.255.255.0";
char *gateway = "192.168.10.1";
if(SetIfAddr("eth0", ip, mask, gateway) < 0)
{
printf("SetIfAddr fail !\n");
}
GetIfAddr("eth0");
//GetIfAllAddr();
return 0;
}
/*
************************************************************************************
* use methord:
* 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;
* };
* # define ifr_name ifr_ifrn.ifrn_name // interface name
* # define ifr_hwaddr ifr_ifru.ifru_hwaddr // MAC address
* # define ifr_addr ifr_ifru.ifru_addr // address
* # define ifr_dstaddr ifr_ifru.ifru_dstaddr // other end of p-p lnk
* # define ifr_broadaddr ifr_ifru.ifru_broadaddr // broadcast address
* # define ifr_netmask ifr_ifru.ifru_netmask // interface net mask
* # define ifr_flags ifr_ifru.ifru_flags // flags
* # define ifr_metric ifr_ifru.ifru_ivalue // metric
* # define ifr_mtu ifr_ifru.ifru_mtu // mtu
* # define ifr_map ifr_ifru.ifru_map // device map
* # define ifr_slave ifr_ifru.ifru_slave // slave device
* # define ifr_data ifr_ifru.ifru_data // for use by interface
* # define ifr_ifindex ifr_ifru.ifru_ivalue // interface index
* # define ifr_bandwidth ifr_ifru.ifru_ivalue // link bandwidth
* # define ifr_qlen ifr_ifru.ifru_ivalue // queue length
* # define ifr_newname ifr_ifru.ifru_newname // New name
* # define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
* # define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
* # define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)
*
*
* 通过ioctl()函数调用请求参数表:
* ---------------------------------------------------------------------------------------------------------
* | 类别 | Request | 说明 | 数据类型 |
* ---------------------------------------------------------------------------------------------------------
* | 套 | SIOCATMARK | 是否位于带外标记 | int |
* | 接 | SIOCSPGRP | 设置套接口的进程ID或进程组ID | int |
* | 口 | SIOCGPGRP | 获取套接口的进程ID或进程组ID | int |
* ---------------------------------------------------------------------------------------------------------
* | | FIONBIN | 设置/清除非阻塞I/O标志 | int |
* | 文 | FIOASYNC | 设置/清除信号驱动异步I/O标志 | int |
* | | FIONREAD | 获取接收缓存区的字节数 | int |
* | 件 | FIOSETOWN | 设置文件的进程ID或进程组ID | int |
* | | FIOGETOWN | 获取文件的进程ID或进程组ID | int |
* ---------------------------------------------------------------------------------------------------------
* | | SIOCGIFCONF | 获取所有接口的清单 | struct ifconf |
* | | SIOCSIFADDR | 设置接口地址 | struct ifreq |
* | | SIOCGIFADDR | 获取接口地址 | struct ifreq |
* | | SIOCSIFFLAGS | 设置接口标志 | struct ifreq |
* | | SIOCGIFFLAGS | 获取接口标志 | struct ifreq |
* | 接 | SIOCSIFDSTADDR | 设置点到点地址 | struct ifreq |
* | | SIOCGIFDSTADDR | 获取点到点地址 | struct ifreq |
* | 口 | SIOCGIFBRDADDR | 获取广播地址 | struct ifreq |
* | | SIOCSIFBRDADDR | 设置广播地址 | struct ifreq |
* | | SIOCGIFNETMASK | 获取子网掩码 | struct ifreq |
* | | SIOCSIFNETMASK | 设置子网掩码 | struct ifreq |
* | | SIOCGIFMETRIC | 获取接口的测度 | struct ifreq |
* | | SIOCSIFMETRIC | 设置接口的测度 | struct ifreq |
* | | SIOCGIFMTU | 获取接口的MTU | struct ifreq |
* | | SIOCxxx | (还有很多取决于系统实现) | struct ifreq |
* -----------------------------------------------------------------------------------------------------------
* | | SIOCSARP | 创建/修改ARP表项 | struct arpreq |
* | ARP | SIOCGARP | 获取ARP表项 | struct arpreq |
* | | SIOCDARP | 删除ARP表项 | struct arpreq |
* ----------------------------------------------------------------------------------------------------------
* | 路 | SIOCADDRT | 增加路径 | struct rtentry|
* | 由 | SIOCDELRT | 删除路径 | struct rtentry|
* ----------------------------------------------------------------------------------------------------------
* | 流 | I_xxx |
* --------------------------------------
*
*
************************************************************************************
*/