Linux下C语言操作网卡的几个代码实例?特别实用
那么如何使用C语言直接操作网口?
比如读写IP地址、读写MAC地址等。
一、原理
主要通过系统用socket()、ioctl()、实现
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定义头文件位于:
/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_IFREQstruct 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*/
二、函数实现
下面将实现不同功能的函数一一列举。
0. 列出所有可用网口
int list_all_port(){ struct ifconf ifconf; struct ifreq *ifr; int m, n, s, fd; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { return -11; } s = sizeof(struct ifreq)*5; for (;;) { ifr = malloc(s); ifconf.ifc_len = s; ifconf.ifc_req = ifr; if (ioctl(fd, SIOCGIFCONF, &ifconf) < 0) { perror("SIOCGIFCONF:"); free(ifr); close(fd); return 1; } if (ifconf.ifc_len != s) break; free(ifr); s *= 2; } close(fd); m = ifconf.ifc_len/sizeof(struct ifreq); for (n = 0; n < m; n++) { printf("port:t%sn",ifconf.ifc_req[n].ifr_name); } free(ifr); }
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)) < 0) { return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) { close(fd); 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)) < 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) < 0) { perror(""); 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)) < 0) { return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { close(fd); 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)) < 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) < 0) { perror("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)) < 0) { return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) { close(fd); 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)) < 0) { return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) { perror(""); 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)) < 0) { return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) { perror(""); 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)) < 0) { return -1; } strcpy(ifr.ifr_name, eth); if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { perror(""); 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:t%sn",ip); getNetMask(ethname,ip); printf("mask:t%sn",ip); setIpAddrManual(ethname, "1.1.1.1"); getLocalIp(ethname,ip); printf("ip:t%sn",ip); setLocalMac(ethname,"00:11:22:33:44:55"); getLocalMac(ethname,mac); printf("mac:t%sn",mac); getMtu(ethname,buf); printf("mtu:t%sn",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)
加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW
或用微信扫描左侧二维码