arping IP冲突问题
2016-04-25 10:08
260 查看
#ifndef __RANDOM_IP_H__ #define __RANDOM_IP_H__ #ifdef __cplusplus #if __cplusplus extern "C"{ #endif #endif #include <sys/time.h> typedef struct { char ip[16]; char gw[16]; char mask[16]; char dns[2][16]; // 保留,暂时没用到 }NetCfg; int abstime_get(struct timeval* timeval); int get_local_ip(const char* if_name, char* local_ip); int set_local_ip(const char* if_name, char* new_ip); int get_random_net(const char *ref_ip, NetCfg* Net); #ifdef __cplusplus #if __cplusplus } #endif #endif #endif
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <net/if.h> #include <linux/sockios.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/if_ether.h> #include <net/if_arp.h> #include <time.h> #include <unistd.h> #include "random_ip.h" #define IF_NAME "eth0" //ARP消息包结构 typedef struct tagArpMsg { struct ethhdr ethhdr; /* Ethernet header */ unsigned short htype; /* hardware type (must be ARPHRD_ETHER) */ unsigned short ptype; /* protocol type (must be ETH_P_IP) */ unsigned char hlen; /* hardware address length (must be 6) */ unsigned char plen; /* protocol address length (must be 4) */ unsigned short operation; /* ARP opcode */ unsigned char sHaddr[6]; /* sender's hardware address */ unsigned char sInaddr[4]; /* sender's IP address */ unsigned char tHaddr[6]; /* target's hardware address */ unsigned char tInaddr[4]; /* target's IP address */ unsigned char pad[18]; /* pad for min. Ethernet payload (60 bytes) */ }ArpMsg; typedef struct { char local_ip[16]; char local_mac[6]; int timeout; // ms NetCfg result; }RunArg; int abstime_get(struct timeval* timeval) { struct timespec tp; if(clock_gettime(CLOCK_MONOTONIC, &tp) < 0) { printf("clock get time error: %s\n", strerror(errno)); return -1; } timeval->tv_sec = tp.tv_sec; timeval->tv_usec = tp.tv_nsec / 1000; return 0; } static char *pr_ether(unsigned char *ptr) { static char buff[64]; snprintf(buff, sizeof(buff), "%02x:%02x:%02x:%02x:%02x:%02x", (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377) ); return (buff); } static int get_mac(const char* if_name, char* mac) { int ret; int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { printf("socket failed by %s\n", strerror(errno)); return -1; } struct ifreq req; memset(&req, 0, sizeof(struct ifreq)); strcpy(req.ifr_name, if_name); ret = ioctl(fd, SIOCGIFHWADDR, &req); if (ret < 0) { printf("ioctl SIOCGIFHWADDR %s failed by %s\n", if_name, strerror(errno)); return -1; } close(fd); struct sockaddr sa; memcpy(&sa, &req.ifr_hwaddr, sizeof(struct sockaddr)); strcpy(mac, pr_ether((unsigned char*)sa.sa_data)); return 0; } static int arpping(unsigned int destIp, unsigned int sourceIp, const char *mac, int timeOutMs) { int ret = 0; /* return value */ int optval = 1; int sockFd = -1; /* socket */ struct sockaddr addr; /* for interface name */ unsigned int iSenderIp; ArpMsg arp; fd_set fdset; struct timeval prevTime; /*socket发送一个arp包*/ if ((sockFd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) { printf("Could not open raw socket.\n"); return -1; } /*设置套接口类型为广播,把这个arp包是广播到这个局域网*/ if (setsockopt(sockFd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) { printf("Could not setsocketopt on raw socket.\n"); close(sockFd); return -1; } /* 对arp设置,这里按照arp包的封装格式赋值即可,详见http://blog.csdn.net/wanxiao009/archive/2010/05/21/5613581.aspx */ memset(&arp, 0, sizeof(arp)); memset(arp.ethhdr.h_dest, 0xff, 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 */ if (destIp == sourceIp) { if (destIp != htonl(0xa9fe010a)) { iSenderIp = htonl(0xa9fe010a); /* Use Reserve IP for Sender */ } else { iSenderIp = htonl(0xa9fe010b); /* Use Reserve IP for Sender */ } } else { iSenderIp = sourceIp; } *((u_int *) arp.sInaddr) = iSenderIp; /* Sender IP address */ memcpy(arp.sHaddr, mac, 6); /* Sender hardware address */ memset(arp.tHaddr, 0xff, 6); /* target hardware address */ *((u_int *) arp.tInaddr) = destIp; /* target IP address */ memset(&addr, 0, sizeof(addr)); strcpy(addr.sa_data, IF_NAME); /*发送arp请求*/ if (sendto(sockFd, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) { printf("arpping sendto failed.\n"); close(sockFd); return -1; } /* 利用select函数进行多路等待*/ abstime_get(&prevTime); while (1) { FD_ZERO(&fdset); FD_SET(sockFd, &fdset); struct timeval timeout = {0, 1000}; ret = select(sockFd + 1, &fdset, NULL, NULL, &timeout); if (ret < 0) { if (errno != EINTR) { ret = -1; break; } } else if (ret == 0) { struct timeval curTime; abstime_get(&curTime); int nSpendTime = (curTime.tv_sec - prevTime.tv_sec) * 1000 + (curTime.tv_usec - prevTime.tv_usec) / 1000; if (nSpendTime >= timeOutMs) { printf("timeout: %d ms\n", nSpendTime); break; } } else if (FD_ISSET(sockFd, &fdset)) { if (recv(sockFd, &arp, sizeof(arp), 0) < 0) { ret = 0; } if (arp.operation == htons(ARPOP_REPLY)) { /*ARP应答有效,说明这个地址是已经存在的*/ if ((memcmp(arp.sHaddr, mac, 6) != 0) && (memcmp(arp.tHaddr, mac, 6) == 0) && (*((u_int *) arp.sInaddr) == destIp)) { printf("Valid arp reply receved for this address.\n"); ret = 1; break; } } } } close(sockFd); return ret; } static int is_ip_conflict(RunArg* run_arg, const char *pCheckIp) { unsigned int destIp = inet_addr(pCheckIp); unsigned int sourceIp = inet_addr(run_arg->local_ip); int ret = arpping(destIp, sourceIp, run_arg->local_mac, run_arg->timeout); return ret; } static int init(RunArg* run_arg) { int ret = -1; run_arg->timeout = 600; int mac[6] = {0}; char szMac[20]; memset(szMac, 0, sizeof(szMac)); ret = get_mac(IF_NAME, szMac); if (ret< 0) { printf("error with: %#x\n", ret); return -1; } printf("mac: %s\n", szMac); sscanf(szMac, "%02x:%02x:%02x:%02x:%02x:%02x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); unsigned int i = 0; for (i = 0; i < sizeof(mac)/sizeof(*mac); i++) { run_arg->local_mac[i] = mac[i]; } ret = get_local_ip(IF_NAME, run_arg->local_ip); if (ret< 0) { printf("error with: %#x\n", ret); return -1; } printf("ipaddr: %s\n", run_arg->local_ip); return 0; } static int random_proc(RunArg* run_arg, const char *ref_ip) { int ret = -1; unsigned int uiIp = 0; unsigned int uiRandomIp = 0; struct in_addr addr; /*检查IP是否合法*/ uiIp = inet_addr(ref_ip); if ((unsigned int) (-1) == uiIp || 0 == uiIp) { printf("invalid ip[%s]\n", ref_ip); return -1; } ret = init(run_arg); if (ret< 0) { printf("error with: %#x\n", ret); return -1; } struct timeval curTime; abstime_get(&curTime); srand(curTime.tv_usec); unsigned int random = rand() % 255; printf("%d\n", random); // 优先修改第四位ip地址,若第四位不够用,则修改第三位(CPU为小端模式) unsigned char old = (uiIp >> 16) & 0xFF; unsigned int i = old; for (i = old; i < 255+old; i++) { unsigned char char_3rd = i % 255; unsigned int ref_ip = ((uiIp & 0xFF00FFFF) | (char_3rd << 16)); unsigned int j = random; for (j = random; j < 255+random; j++) { unsigned char char_4th = j % 255; char_4th = (0 == char_4th) ? 1 : char_4th; printf("char_3rd: %d, j: %d, char_4th: %d\n", char_3rd, j, char_4th); uiRandomIp = ((ref_ip & 0xFFFFFF) | (char_4th << 24)); if (uiIp == uiRandomIp) { // 与参照的IP地址相同,重新获取随机IP continue; } addr.s_addr = uiRandomIp; memset(run_arg->result.ip, 0, sizeof(run_arg->result.ip)); strncpy(run_arg->result.ip, inet_ntoa(addr), sizeof(run_arg->result.ip)); printf("new ip: %s\n", run_arg->result.ip); ret = is_ip_conflict(run_arg, run_arg->result.ip); if (ret == 0) { // 没有IP冲突 char* gw = rindex(run_arg->result.ip, '.'); if (gw) { memset(run_arg->result.gw, 0, sizeof(run_arg->result.gw)); memcpy(run_arg->result.gw, run_arg->result.ip, gw - run_arg->result.ip); strcat(run_arg->result.gw, ".1"); } strcpy(run_arg->result.mask, "255.255.255.0"); if (i > old) { strcpy(run_arg->result.mask, "255.255.0.0"); } return 0; } } } return -1; } int get_local_ip(const char* if_name, char* local_ip) { int ret; int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { printf("socket failed by %s\n", strerror(errno)); return -1; } struct ifreq req; memset(&req, 0, sizeof(struct ifreq)); strcpy(req.ifr_name, if_name); struct sockaddr_in *sin; sin = (struct sockaddr_in *)&req.ifr_addr; ret = ioctl(fd, SIOCGIFADDR, &req); if (ret < 0 && errno != EADDRNOTAVAIL) { printf("ioctl SIOCSIFADDR %s failed by %s\n", if_name, strerror(errno)); return -1; } close(fd); strcpy(local_ip, inet_ntoa(sin->sin_addr)); return 0; } int set_local_ip(const char* if_name, char* new_ip) { int ret; int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { printf("socket failed by %s\n", strerror(errno)); return -1; } struct ifreq ifr; memset(&ifr, 0, sizeof(struct ifreq)); strcpy(ifr.ifr_name, if_name); struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; inet_aton(new_ip, &addr.sin_addr); memcpy(&ifr.ifr_ifru.ifru_addr, &addr, sizeof(struct sockaddr_in)); ret = ioctl(fd, SIOCSIFADDR, &ifr); if (ret < 0) { printf("ioctl SIOCSIFADDR %s failed by %s\n", if_name, strerror(errno)); return -1; } close(fd); return 0; } int get_random_net(const char *ref_ip, NetCfg* Net) { RunArg run_arg; memset(&run_arg, 0, sizeof(run_arg)); memset(Net, 0, sizeof(NetCfg)); int ret = random_proc(&run_arg, ref_ip); if (ret < 0) { printf("random_proc failed, ret=%d\n", ret); return -1; } memcpy(Net, &run_arg.result, sizeof(*Net)); return 0; } static int auto_adjust_net(char* peer_ip) { static struct timeval last_adjust = {0, 0}; int ret = -1; NetCfg result; memset(&result, 0, sizeof(result)); struct timeval cur = {0, 0}; abstime_get(&cur); int pass_time = (cur.tv_sec - last_adjust.tv_sec)*1000 + (cur.tv_usec - last_adjust.tv_usec)/1000; if (pass_time < 5000) { printf("too many discovery package,pass_time=%d ms\n", pass_time); return -1; } memcpy(&last_adjust, &cur, sizeof(cur)); char local_ip[16]; memset(local_ip, 0, sizeof(local_ip)); ret = get_local_ip("eth0", local_ip); if (ret < 0) { printf("failed to get_local_ip with %#x\n", ret); return -1; } char* find = rindex(local_ip, '.'); if (find) { char temp[2][16]; memset(temp, 0, sizeof(temp)); strncpy(temp[0], local_ip, find-local_ip); find = rindex(peer_ip, '.'); strncpy(temp[1], peer_ip, find-peer_ip); if (!strcmp(temp[0], temp[1])) { //同网段,不用修改 printf("reference ip[%s] is same network with local ip[%s]\n", peer_ip, local_ip); return -1; } } ret = get_random_net(peer_ip, &result); if (ret < 0) { printf("failed to adjust net with %#x\n", ret); return -1; } printf("random ip addr: %s\n", result.ip); printf("random gw addr: %s\n", result.gw); printf("random mask addr: %s\n", result.mask); return 0; } int main() { auto_adjust_net("192.168.11.5"); return 0; }
相关文章推荐
- 按钮倒计时
- setenv (NLS_LANG="AMERICAN_AMERICA.ZHS16GBK")
- 从为什么String=String谈到StringBuilder和StringBuffer
- 北大计算机课程体系
- BCGSoft Demo示例展示之一般示例集合(1/2)
- 产生随机字符串
- JAVA--抽象工厂模式--设计模式二
- Laravel 4 入门三讲(上)laravel 在启动的时候到底做了什么?
- java和ibatis调用存储过程并取得返回值
- Entity Framework 中的Code First 中引入数据库函数
- 信号处理(一)——能量信号与功率信号的区别
- 杂货
- pip自动生成requirements.txt依赖关系清单
- HDU 5438 Ponds
- Mlond的到来(android)
- DLL+ ActiveX控件+WEB页面调用例子
- ACM-ICPC是什么样的比赛
- Redis键时间老化的测试
- C++ using关键字作用
- MyBatis+MySQL数据库操作小技巧