Linux下IP衝突檢測程式原始碼及分析(利用免費arp)---感謝原作者
阿新 • • 發佈:2019-02-14
由於沒有找到原始碼的原作者, 所以就給出一個間接的轉載地址:http://blog.csdn.net/wanxiao009/article/details/5622296, 再次感謝原始碼原作者
該程式執行在linux環境下,可以檢測ip衝突, 我試過, 挺靠譜的,現摘錄如下:(該程式涉及免費arp, 關於免費arp的概念和原理, 請自己在網上學習)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <time.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <net/if.h> #include <net/if_arp.h> #include <arpa/inet.h> #define MAC_BCAST_ADDR (unsigned char *) "/xff/xff/xff/xff/xff/xff" #define ETH_INTERFACE "eth0" struct arpMsg { struct ethhdr ethhdr; /* Ethernet header */ u_short htype; /* hardware type (must be ARPHRD_ETHER) */ u_short ptype; /* protocol type (must be ETH_P_IP) */ u_char hlen; /* hardware address length (must be 6) */ u_char plen; /* protocol address length (must be 4) */ u_short operation; /* ARP opcode */ u_char sHaddr[6]; /* sender's hardware address */ u_char sInaddr[4]; /* sender's IP address */ u_char tHaddr[6]; /* target's hardware address */ u_char tInaddr[4]; /* target's IP address */ u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */ }; struct server_config_t { u_int32_t server; /* Our IP, in network order */ u_int32_t start; /* Start address of leases, network order */ u_int32_t end; /* End of leases, network order */ struct option_set *options; /* List of DHCP options loaded from the config file */ char *interface; /* The name of the interface to use */ int ifindex; /* Index number of the interface to use */ unsigned char arp[6]; /* Our arp address */ unsigned long lease; /* lease time in seconds (host order) */ unsigned long max_leases; /* maximum number of leases (including reserved address) */ char remaining; /* should the lease file be interpreted as lease time remaining, or * as the time the lease expires */ unsigned long auto_time; /* how long should udhcpd wait before writing a config file. * if this is zero, it will only write one on SIGUSR1 */ unsigned long decline_time; /* how long an address is reserved if a client returns a * decline message */ unsigned long conflict_time; /* how long an arp conflict offender is leased for */ unsigned long offer_time; /* how long an offered address is reserved */ unsigned long min_lease; /* minimum lease a client can request*/ char *lease_file; char *pidfile; char *notify_file; /* What to run whenever leases are written */ u_int32_t siaddr; /* next server bootp option */ char *sname; /* bootp server name */ char *boot_file; /* bootp boot file option */ }; struct server_config_t server_config; /*引數分別表示 網絡卡裝置型別 介面檢索索引 主機IP地址 主機arp地址*/ int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp) { int fd; /*ifreq結構定義在/usr/include/net/if.h,用來配置ip地址,啟用介面,配置MTU等介面資訊的。 其中包含了一個介面的名字和具體內容——(是個共用體,有可能是IP地址,廣播地址,子網掩碼,MAC號,MTU或其他內容)。 ifreq包含在ifconf結構中。而ifconf結構通常是用來儲存所有介面的資訊的。 */ struct ifreq ifr; struct sockaddr_in *our_ip; memset(&ifr, 0, sizeof(struct ifreq)); /*建立一個socket函式,SOCK_RAW是為了獲取第三個引數的IP包資料, IPPROTO_RAW提供應用程式自行指定IP頭部的功能。 */ if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) { ifr.ifr_addr.sa_family = AF_INET; /*將網絡卡型別賦值給ifr_name*/ strcpy(ifr.ifr_name, interface); if (addr) { /*SIOCGIFADDR用於檢索介面地址*/ if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { /*獲取本機IP地址,addr是一個指向該地址的指標*/ our_ip = (struct sockaddr_in *) &ifr.ifr_addr; *addr = our_ip->sin_addr.s_addr; printf("%s (our ip) = %s/n", ifr.ifr_name, inet_ntoa(our_ip->sin_addr)); } else { printf("SIOCGIFADDR failed, is the interface up and configured?: %s/n", strerror(errno)); return -1; } } /*SIOCGIFINDEX用於檢索介面索引*/ if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) { printf("adapter index %d/n", ifr.ifr_ifindex); /*指標ifindex 獲取索引*/ *ifindex = ifr.ifr_ifindex; } else { printf("SIOCGIFINDEX failed!: %s/n", strerror(errno)); return -1; } /*SIOCGIFHWADDR用於檢索硬體地址*/ if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) { /*所獲取的硬體地址複製到結構server_config的陣列arp[6]引數中*/ memcpy(arp, ifr.ifr_hwaddr.sa_data, 6); printf("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x/n", arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]); } else { printf("SIOCGIFHWADDR failed!: %s/n", strerror(errno)); return -1; } } else { printf("socket failed!: %s/n", strerror(errno)); return -1; } close(fd); return 0; } /*引數說明 目標IP地址,本機IP地址,本機mac地址,網絡卡型別*/ int arpping(u_int32_t yiaddr, u_int32_t ip, unsigned char *mac, char *interface) { int timeout = 2; int optval = 1; int s; /* socket */ int rv = 1; /* return value */ struct sockaddr addr; /* for interface name */ struct arpMsg arp; fd_set fdset; struct timeval tm; time_t prevTime; /*socket傳送一個arp包*/ if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) { printf("Could not open raw socket/n"); return -1; } /*設定套介面型別為廣播,把這個arp包是廣播到這個區域網*/ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) { printf("Could not setsocketopt on raw socket/n"); close(s); return -1; } /* 對arp設定,這裡按照arp包的封裝格式賦值即可,詳見http://blog.csdn.net/wanxiao009/archive/2010/05/21/5613581.aspx */ memset(&arp, 0, sizeof(arp)); memcpy(arp.ethhdr.h_dest, MAC_BCAST_ADDR, 6); /* MAC DA */ memcpy(arp.ethhdr.h_source, mac, 6); /* MAC SA */ arp.ethhdr.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */ arp.htype = htons(ARPHRD_ETHER); /* hardware type */ arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */ arp.hlen = 6; /* hardware address length */ arp.plen = 4; /* protocol address length */ arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ *((u_int *) arp.sInaddr) = ip; /* source IP address */ memcpy(arp.sHaddr, mac, 6); /* source hardware address */ *((u_int *) arp.tInaddr) = yiaddr; /* target IP address */ memset(&addr, 0, sizeof(addr)); strcpy(addr.sa_data, interface); /*傳送arp請求*/ if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) rv = 0; /* 利用select函式進行多路等待*/ tm.tv_usec = 0; time(&prevTime); while (timeout > 0) { FD_ZERO(&fdset); FD_SET(s, &fdset); tm.tv_sec = timeout; if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) { printf("Error on ARPING request: %s/n", strerror(errno)); if (errno != EINTR) rv = 0; } else if (FD_ISSET(s, &fdset)) { if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0; /*如果條件 htons(ARPOP_REPLY) bcmp(arp.tHaddr, mac, 6) == 0 *((u_int *) arp.sInaddr) == yiaddr 三者都為真,則ARP應答有效,說明這個地址是已近存在的*/ if (arp.operation == htons(ARPOP_REPLY) && bcmp(arp.tHaddr, mac, 6) == 0 && *((u_int *) arp.sInaddr) == yiaddr) { printf("Valid arp reply receved for this address/n"); rv = 0; break; } } timeout -= time(NULL) - prevTime; time(&prevTime); } close(s); return rv; } int check_ip(u_int32_t addr) { struct in_addr temp; if (arpping(addr, server_config.server, server_config.arp, ETH_INTERFACE) == 0) { temp.s_addr = addr; printf("%s belongs to someone, reserving it for %ld seconds/n", inet_ntoa(temp), server_config.conflict_time); return 1; } else return 0; } int main(int argc, char *argv[]) { if(argc < 2) { printf("Usage: checkip ipaddr/n"); exit(0); } /*讀乙太網介面函式,獲取一些配置資訊*/ if (read_interface(ETH_INTERFACE, &server_config.ifindex, &server_config.server, server_config.arp) < 0) { exit(0); } /*IP檢測函式*/ if(check_ip(inet_addr(argv[1])) == 0) { printf("IP:%s can use/n", argv[1]); } else { printf("IP:%s conflict/n", argv[1]); } return 0; }
再次, 真心贊一個原作者