您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: