#include <stdio.h>
//printf()
#include <unistd.h>
//ioctl()
#include <sys/ioctl.h>
//ioctl
#include <sys/socket.h>
//socket()
#include <net/if.h>
//struct ifconf{} & struct ifreq{}
#include <string.h>
//strcpy()
#include <arpa/inet.h>
//inet_ntoa()
#include <stdlib.h>
//malloc() & free()
int print_if_addr(int fd, char *interface_name);
//打印接口的ip地址
int print_if_mac(int fd, char *interface_name);
//打印接口的mac地址
int print_if_broadaddr(int fd, char *interface_name);
//打印接口的广播地址
int print_if_mask(int fd, char *interface_name);
//打印接口的掩码
int print_if_mtu(int fd, char *interface_name);
//打印接口的mtu
int print_all_interface();
//打印所有接口的基本信息
int print_if_addr6(char *interface_name);
//打印接口的ipv6地址
int print_interface_info(char *interface_name);
//打印接口的以上所有信息
int set_if_up(char *interface_name);
//启动接口
int set_if_down(char *interface_name);
//关闭接口
int set_if_ip(char *interface_name, char *ip_str);
//设置接口的ip地址
void usage();
//打印该程序的使用手册
int main(int argc, char **argv)
{
int sockfd;
printf("\n
**********funway:用ioctl函数来实现ifconfig命令的效果**********\n");
switch(argc)
{
case 1:
print_all_interface();
break;
case 2:
print_interface_info(argv[1]);
break;
case 3:
if(strcmp(argv[2], "up") == 0)
set_if_up(argv[1]);
else if(strcmp(argv[2], "down") == 0)
set_if_down(argv[1]);
else
set_if_ip(argv[1], argv[2]);
break;
default:
usage();
break;
}
return 0;
}
void usage()
{
printf("usage: ./myifconfig [interface [down|up|ip]]\n");
}
int print_if_addr(int fd, char *if_name)
{
struct sockaddr_in *ip;
struct ifreq ifr;
strcpy(ifr.ifr_name, if_name);
if(ioctl(fd, SIOCGIFADDR, &ifr) < 0)
{
perror("ioctl SIOCGIFADDR error");
return -1;
}
ip = (struct sockaddr_in *)&ifr.ifr_addr;
//获得ipv4地址
printf("
IP: %s\n", inet_ntoa(ip->sin_addr));
//将ipv4地址转换为主机字节序的字符串并输出
return 0;
}
int print_if_broadaddr(int fd, char *if_name)
{
struct sockaddr_in *ip;
struct ifreq ifr;
strcpy(ifr.ifr_name, if_name);
if(ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
{
perror("ioctl SIOCGIFBRDADDR error");
return -1;
}
ip = (struct sockaddr_in *)&ifr.ifr_broadaddr;
//获得广播地址
printf("
Broadcast: %s\n", inet_ntoa(ip->sin_addr));
return 0;
}
int print_if_mask(int fd, char *if_name)
{
struct sockaddr_in *ip;
struct ifreq ifr;
strcpy(ifr.ifr_name, if_name);
if(ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
{
perror("ioctl SIOCGIFNETMASK error");
return -1;
}
ip = (struct sockaddr_in *)&ifr.ifr_ifru.ifru_netmask;
//获得子网掩码。注意!我们仍放在struct aockaddr_in结构中返回
printf("
Mask: %s\n", inet_ntoa(ip->sin_addr));
return 0;
}
int print_if_mac(int fd, char *if_name)
{
unsigned char *p;
//注意! 这里要用unsigned char,而不是char!因为char要对[1xxx xxxx]这样的数进行补码运算的。
//但我们等下要打印的mac地址是不需要符号的数值
struct ifreq ifr;
strcpy(ifr.ifr_name, if_name);
if(ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
{
perror("ioctl SIOCGIFHWADDR error");
return -1;
}
p = (char *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];
//获得接口的MAC地址,用字符串指针返回
printf("
MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5));
//printf(" MAC:%02x:%02x:%02x:%02x:%02x:%02x\n", *p++, *p++, *p++, *p++, *p++, *p++);
//这么写会导致输出为倒序。这并不是p指针有什么问题,不信你可以用
// for(;;)
//
printf(p++);
//来试验就是正确的,我猜倒序的原因是编译器的优化问题吧
return 0;
}
int print_if_mtu(int fd, char *if_name)
{
unsigned int mtu;
struct ifreq ifr;
strcpy(ifr.ifr_name, if_name);
if(ioctl(fd, SIOCGIFMTU, &ifr) < 0)
{
perror("ioctl SIOCGIFMTU error");
return -1;
}
mtu = ifr.ifr_ifru.ifru_mtu;
//获得子网掩码。注意!我们仍放在struct aockaddr_in结构中返回
printf("
MTU: %d\n", mtu);
return 0;
}
int print_if_addr6(char *if_name)
{
unsigned int mtu;
struct ifreq ifr;
int sockfd;
if((sockfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
{
perror("Socket error");
return -1;
}
// 创建用来检查网络接口的套接字
/*
strcpy(ifr.ifr_name, if_name);
if(ioctl(fd, SIOCGIFMTU, &ifr) < 0)
{
perror("ioctl SIOCGIFMTU error");
return -1;
}
mtu = ifr.ifr_ifru.ifru_mtu;
//获得子网掩码。注意!我们仍放在struct aockaddr_in结构中返回
printf("
ipv6: %d\n", mtu);
*/
//未写完,不知道怎么获得ipv6地址。。。
return 0;
}
int print_all_interface()
{
struct ifconf ifc;
struct ifreq *ifr_p;
int sockfd, len, old_len = 0, i;
char *buf;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Socket error");
return -1;
}
// 创建用来检查网络接口的套接字
len = 10 * sizeof(struct ifreq);
for( ; ; )
{
if((buf = malloc(len)) == NULL)
{
perror("malloc error");
return -1;
}
ifc.ifc_len = len;
ifc.ifc_buf = buf;
if(ioctl(sockfd, SIOCGIFCONF, &ifc) < 0)
{
perror("ioctl SIOCGIFCONF error");
return -1;
}
if(ifc.ifc_len == old_len)
break;
old_len = ifc.ifc_len;
len += 10 * sizeof(struct ifreq);
free(buf);
}
printf("we have %d interfaces\n", ifc.ifc_len / sizeof(struct ifreq));
for(i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++)
{
ifr_p = &ifc.ifc_req[i];
printf("\ninterface [%s]:\n", ifr_p->ifr_name);
print_if_addr(sockfd, ifr_p->ifr_name);
print_if_broadaddr(sockfd, ifr_p->ifr_name);
print_if_mask(sockfd, ifr_p->ifr_name);
print_if_mac(sockfd, ifr_p->ifr_name);
print_if_mtu(sockfd, ifr_p->ifr_name);
}
close(sockfd);
return 0;
}
int print_interface_info(char *if_name)
{
int sockfd;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Socket error");
return -1;
}
// 创建用来检查网络接口的套接字
printf("%s:\n", if_name);
print_if_addr(sockfd, if_name);
print_if_broadaddr(sockfd, if_name);
print_if_mask(sockfd, if_name);
print_if_mac(sockfd, if_name);
print_if_mtu(sockfd, if_name);
close(sockfd);
return 0;
}
int set_if_up(char *if_name)
//启动接口
{
struct ifreq ifr;
int sockfd;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Socket error");
return -1;
}
// 创建用来检查网络接口的套接字
strcpy(ifr.ifr_name, if_name);
if(ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
{
perror("ioctl SIOCGIFFLAGS error");
return -1;
}
ifr.ifr_flags |= IFF_UP;
if(ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0)
{
perror("ioctl SIOCSIFFLAGS error");
return -1;
}
return 0;
}
int set_if_down(char *if_name)
//关闭接口
{
struct ifreq ifr;
int sockfd;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Socket error");
return -1;
}
// 创建用来检查网络接口的套接字
strcpy(ifr.ifr_name, if_name);
if(ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
{
perror("ioctl SIOCGIFFLAGS error");
return -1;
}
ifr.ifr_flags &= ~IFF_UP;
//将IIF_UP取反后与原来的标志进行 与运算。
if(ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0)
{
perror("ioctl SIOCSIFFLAGS error");
return -1;
}
return 0;
}
int set_if_ip(char *if_name, char *ip_str)
//设置接口的ip地址
{
struct ifreq ifr;
struct sockaddr_in ip_addr;
int sockfd;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Socket error");
return -1;
}
// 创建用来检查网络接口的套接字
ip_addr.sin_family = AF_INET;
if(inet_pton(AF_INET, ip_str, &ip_addr.sin_addr) < 1)
{
perror("error ipv4 addr:");
return -1;
}
strcpy(ifr.ifr_name, if_name);
memcpy(&ifr.ifr_addr, &ip_addr, sizeof(struct sockaddr_in));
if(ioctl(sockfd, SIOCSIFADDR, &ifr) < 0)
{
perror("ioctl SIOCSIFADDR error");
return -1;
}
return 0;
}