下面是对原文的重新表述,重点在于如何用c语言直接操作网络接口,例如读写ip地址和mac地址。
如何使用c语言直接操作网络接口?
在这篇文章中,我们将讨论如何在C语言中直接操作网络接口。这包括读取和修改IP地址、MAC地址等信息。
1. 基本原理
我们可以通过使用系统提供的socket()和ioctl()函数来实现这些操作。这些函数允许我们与网络接口进行直接的交互,从而获取和设置与网络有关的各种参数。
你可以通过使用这些C语言函数来控制和管理当前系统上的网络接口。通过这两种系统调用,我们可以轻松实现网络接口的操作和管理。
int socket(int domain, int type, int protocol); 功能: 创建套接字 参数: domain: Name Purpose Man page AF_UNIX, AF_LOCAL Local communication unix(7) AF_INET IPv4 Internet protocols ip(7) type: SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mecha‐ nism may be supported. SOCK_DGRAM Supports datagrams (connectionless, unreliable messages of a fixed maximum length). protocol: 通常为0 返回值: 成功:新的套接字的文件描述符 失败:错误码,负值 int ioctl(int fd, unsigned long request, ...); 参数: fd :文件描述符 request:命令 ... :参数
其中网络用到的request定义头文件位于:
立即学习“C语言免费学习笔记(深入)”;
/usr/include/Linux/sockios.h /* Linux-specific socket ioctls */ #define SIOCINQ FIONREAD #define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */ /* Routing table calls. */ #define SIOCADDRT 0x890B /* add routing table entry */ #define SIOCDELRT 0x890C /* delete routing table entry */ #define SIOCRTMSG 0x890D /* call to routing system */ /* Socket configuration controls. */ #define SIOCGIFNAME 0x8910 /* get iface name */ #define SIOCSIFLINK 0x8911 /* set iface channel */ #define SIOCGIFCONF 0x8912 /* get iface list */ #define SIOCGIFFLAGS 0x8913 /* get flags */ #define SIOCSIFFLAGS 0x8914 /* set flags */ #define SIOCGIFADDR 0x8915 /* get PA address */ #define SIOCSIFADDR 0x8916 /* set PA address */ #define SIOCGIFDSTADDR 0x8917 /* get remote PA address */ #define SIOCSIFDSTADDR 0x8918 /* set remote PA address */ #define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ #define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ #define SIOCGIFNETMASK 0x891b /* get network PA mask */ #define SIOCSIFNETMASK 0x891c /* set network PA mask */ #define SIOCGIFMETRIC 0x891d /* get metric */ #define SIOCSIFMETRIC 0x891e /* set metric */ #define SIOCGIFMEM 0x891f /* get memory address (BSD) */ #define SIOCSIFMEM 0x8920 /* set memory address (BSD) */ #define SIOCGIFMTU 0x8921 /* get MTU size */ #define SIOCSIFMTU 0x8922 /* set MTU size */ #define SIOCSIFNAME 0x8923 /* set interface name */ #define SIOCSIFHWADDR 0x8924 /* set hardware address */ #define SIOCGIFENCAP 0x8925 /* get/set encapsulations */ #define SIOCSIFENCAP 0x8926 #define SIOCGIFHWADDR 0x8927 /* Get hardware address */ #define SIOCGIFSLAVE 0x8929 /* Driver slaving support */ #define SIOCSIFSLAVE 0x8930 #define SIOCADDMULTI 0x8931 /* Multicast address lists */ #define SIOCDELMULTI 0x8932 #define SIOCGIFINDEX 0x8933 /* name -> if_index mapping */ #define SIOGIFINDEX SIOCGIFINDEX /* misprint compatibility :-) */ #define SIOCSIFPFLAGS 0x8934 /* set/get extended flags set */ #define SIOCGIFPFLAGS 0x8935 #define SIOCDIFADDR 0x8936 /* delete PA address */ #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */ #define SIOCGIFCOUNT 0x8938 /* get number of devices */ ……
其中ioctl的参数需要借助结构体struct ifreq, 定义头文件:
/usr/include/linux/if.h #if __UAPI_DEF_IF_IFREQ Struct ifreq { #define IFHWADDRLEN 6 union { char ifrn_name[IFNAMSIZ]; /* if 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 ifru_flags; int ifru_ivalue; int ifru_mtu; struct ifmap ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ char ifru_newname[IFNAMSIZ]; void * ifru_data; struct if_settings ifru_settings; } ifr_ifru; }; #endif /* __UAPI_DEF_IF_IFREQ */ #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 ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
二、函数实现
下面将实现不同功能的函数一一列举。
1. 获取本机网卡IP
int getLocalIp(const char *eth, char *ip) { struct ifreq ifr; struct sockaddr_in sin; int fd; bzero(&ifr, sizeof(ifr)); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFADDR, &ifr) return -1; } memcpy(&sin, &ifr.ifr_addr, sizeof(sin)); snprintf(ip, IP_SIZE, "%s", inet_ntoa(sin.sin_addr)); close(fd); return 0; }
2. 设置本网卡IP地址
int setIpAddrManual(const char *eth, char *ipstr) { int fd; struct sockaddr_in sin; struct ifreq ifr; bzero(&ifr, sizeof(ifr)); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) return -1; } strcpy(ifr.ifr_name, eth); sin.sin_addr.s_addr = inet_addr(ipstr); sin.sin_family = AF_INET; memcpy(&ifr.ifr_addr, &sin, sizeof(sin)); if (ioctl(fd, SIOCSIFADDR, &ifr) ""); close(fd); return -1; } close(fd); return 0; }
3. 获取本机网卡Mac地址
int getLocalMac(const char *eth, char *mac) { int fd; struct ifreq ifr; bzero(&ifr, sizeof(ifr)); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFHWADDR, &ifr) return -1; } snprintf(mac,18, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned char) ifr.ifr_hwaddr.sa_data[0], (unsigned char) ifr.ifr_hwaddr.sa_data[1], (unsigned char) ifr.ifr_hwaddr.sa_data[2], (unsigned char) ifr.ifr_hwaddr.sa_data[3], (unsigned char) ifr.ifr_hwaddr.sa_data[4], (unsigned char) ifr.ifr_hwaddr.sa_data[5]); close(fd); return 0; }
4. 设置网卡mac地址
/* support format [00:11:22:33:44:55] */ #define MAC_ARRAY(mac_array) (unsigned int *)&mac_array[0],(unsigned int *)&mac_array[1],(unsigned int *)&mac_array[2],(unsigned int *)&mac_array[3],(unsigned int *)&mac_array[4],(unsigned int *)&mac_array[5] int setLocalMac(const char *eth, char *mac) { int fd; struct ifreq ifr; unsigned char mac_array[6] = {0}; bzero(&ifr, sizeof(ifr)); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) return -1; } strcpy(ifr.ifr_name, eth); ifr.ifr_hwaddr.sa_family = AF_LOCAL; sscanf(mac,"%02x:%02x:%02x:%02x:%02x:%02x", MAC_ARRAY(mac_array)); memcpy(ifr.ifr_hwaddr.sa_data,mac_array,6); if (ioctl(fd, SIOCSIFHWADDR, &ifr) "SIOCSIFHWADDR:"); close(fd); return -1; } close(fd); return 0; }
注意:
- 网卡地址的第一字节必须是偶数
- sa_family 值必须为:AF_LOCAL
5. 获取网卡mtu
int getMtu(const char *eth, char *mtu) { int fd; struct ifreq ifr; bzero(&ifr, sizeof(ifr)); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFMTU, &ifr) return -1; } snprintf(mtu,64, "%d", (unsigned char) ifr.ifr_mtu); close(fd); return 0; }
6. 获取广播地址
int getBroadAddr(const char *eth, char *ip) { int fd; struct sockaddr_in sin; struct ifreq ifr; bzero(&ifr, sizeof(ifr)); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFBRDADDR, &ifr) ""); close(fd); return -1; } memcpy(&sin, &ifr.ifr_broadaddr, sizeof(sin)); snprintf(ip, IP_SIZE, "%s", inet_ntoa(sin.sin_addr)); close(fd); return 0; }
7. 获取掩码
int getNetMask(const char *eth, char *mask) { int fd; struct sockaddr_in sin; struct ifreq ifr; bzero(&ifr, sizeof(ifr)); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFNETMASK, &ifr) ""); close(fd); return -1; } memcpy(&sin, &ifr.ifr_netmask, sizeof(sin)); snprintf(mask, IP_SIZE, "%s", inet_ntoa(sin.sin_addr)); close(fd); return 0; }
8. 获取网卡flag
int getFlags(const char *eth, char *fg) { int fd; struct sockaddr_in sin; struct ifreq ifr; bzero(&ifr, sizeof(ifr)); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFFLAGS, &ifr) ""); close(fd); return -1; } snprintf(fg, IP_SIZE, "%x", ifr.ifr_flags); close(fd); return 0; }
三、测试
1. 测试程序
int main(int argc, char **argv) { int fg=0; char mac[32]={}; char ip[IP_SIZE]={0}; char buf[64]; getBroadAddr(ethname,ip); printf("broad ip: %s ",ip); getNetMask(ethname,ip); printf("mask: %s ",ip); setIpAddrManual(ethname, "1.1.1.1"); getLocalIp(ethname,ip); printf("ip: %s ",ip); setLocalMac(ethname,"00:11:22:33:44:55"); getLocalMac(ethname,mac); printf("mac: %s ",mac); getMtu(ethname,buf); printf("mtu: %s ",buf); return 1; }
2. 执行结果
执行后结果:
peng@ubuntu:~/work/test/ip$ ifconfig eth0 Link encap:Ethernet HWaddr 00:11:22:33:44:55 inet addr:1.1.1.1 Bcast:1.255.255.255 Mask:255.0.0.0 inet6 addr: fe80::d9d4:d42b:a04a:9d40/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:188577 errors:0 dropped:0 overruns:0 frame:0 TX packets:208116 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:53762370 (53.7 MB) TX bytes:172094089 (172.0 MB)
完整代码,后天回复:eth