下面是對原文的重新表述,重點在于如何用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