首页 > 系统相关 >如何在linux下检测(自身)IP冲突

如何在linux下检测(自身)IP冲突

时间:2022-09-28 19:47:51浏览次数:49  
标签:ifr int IP 0x00 char mac 冲突 linux include

  最近遇到一个需求,或者说是一个用户现场问题。

  我们设备先安装,设置dhcp模式获取ip进行联网,后来又安装了其他设备,但该设备是手动设置的静态ip地址,正好与我们设备冲突,造成网络故障。

 

  那我们就需要有一个能够检测ip冲突的方法,这个可以使用ARP协议的ACD功能(Address Conflict Detection,在RFC 5227中提出)。

  (ARP协议主要用于局域网IP地址与MAC地址转换,因为我们网络主机之间收发数据其实是使用的硬件地址而非IP地址;向外网发数据时其实就是发给网关,网关再发给网关以此类推)

 

  ACD功能中使用ARP Request的不同两种参数填充方式分别作为ARP Probe和ARP Announcement,后者是告诉别人我要用某个IP地址了,前者是闻讯局域网内是否有人已经用了某个IP地址。

  因此我们可以使用ARP Probe来检测IP冲突。

 

  当我们通过网卡向局域网广播ARP Probe时,如果其他主机使用了我们闻讯的IP地址,则会响应,我们就知道IP冲突了。

  代码如下

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <errno.h>
  5 #include <sys/types.h>
  6 #include <sys/socket.h>
  7 #include <linux/if_packet.h>
  8 #include <netdb.h>
  9 #include <unistd.h>
 10 #include <arpa/inet.h>
 11 #include <sys/ioctl.h>
 12 #include <net/ethernet.h>
 13 #include <netinet/ether.h>
 14 #include <net/if.h>
 15 #include <netinet/ip.h>
 16 #include <sys/ioctl.h>
 17 #include <net/if.h>
 18 #include <netinet/in.h>
 19 #include <netdb.h>
 20 #include <sys/time.h>
 21 
 22 static int get_mac(const char *if_name, char *mac);
 23 static int get_ifidx(const char *if_name, int *idx);
 24 
 25 int main(int argc, char *argv[])
 26 {
 27     if (argc < 3)
 28     {
 29         printf("Usage: %s if_name detect_ip\n\tLike: %s wlan0 192.168.0.211\n", argv[0], argv[0]);
 30         exit(EXIT_FAILURE);
 31     }
 32 
 33     const char *if_name = argv[1];
 34     const char *dst_ip = argv[2];
 35 
 36     unsigned int ip4bit = 0;
 37     {
 38         struct in_addr addr = {0};
 39         if (inet_aton(dst_ip, &addr) == 0)
 40         {
 41             perror("inet_aton");
 42             exit(EXIT_FAILURE);
 43         }
 44         ip4bit = addr.s_addr;
 45     }
 46 
 47     char mac[6] = {0};
 48     if (get_mac(if_name, mac) != 0)
 49     {
 50         perror("inet_aton");
 51         exit(EXIT_FAILURE);
 52     }
 53 
 54     int sock_client = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 55     if (sock_client < 0)
 56     {
 57         perror("socket");
 58         exit(EXIT_FAILURE);
 59     }
 60     int sock_server;
 61     if ((sock_server = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) < 0)
 62     {
 63         perror("cannot create socket");
 64         exit(EXIT_FAILURE);
 65     }
 66     struct timeval tv_out;
 67     tv_out.tv_sec = 1;
 68     tv_out.tv_usec = 0;
 69     setsockopt(sock_server, SOL_SOCKET, SO_RCVTIMEO, &tv_out, sizeof(tv_out));
 70 
 71     unsigned char arp_probe_msg[] = {
 72         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*目的mac地址*/
 73         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*源mac地址*/
 74         0x08, 0x06,                         /*帧类型*/
 75 
 76         /*ARP报文头部(28个字节)*/
 77         0x00, 0x01,                         /*硬件类型*/
 78         0x08, 0x00,                         /*协议类型*/
 79         6,                                  /*硬件地址长度*/
 80         4,                                  /*协议地址长度*/
 81         0x00, 0x01,                         /*ARP请求*/
 82         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*源mac地址*/
 83         0, 0, 0, 0,                         /*源IP*/
 84         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*目的mac地址*/
 85         0, 0, 0, 0                          /*目的IP*/
 86     };
 87 
 88     memcpy(arp_probe_msg + 6, mac, 6);
 89     memcpy(arp_probe_msg + 22, mac, 6);
 90     memcpy(arp_probe_msg + 38, &ip4bit, 4);
 91 
 92     int if_idx;
 93     if (get_ifidx(if_name, &if_idx) != 0)
 94         exit(EXIT_FAILURE);
 95 
 96     // 发送5次
 97     for (int i = 0; i < 5; ++i)
 98     {
 99         struct sockaddr_ll sll;
100         bzero(&sll, sizeof(sll));
101         sll.sll_ifindex = if_idx;
102 
103         if (sendto(sock_client, arp_probe_msg, sizeof arp_probe_msg, 0, (struct sockaddr *)&sll, sizeof(sll)) < sizeof arp_probe_msg)
104         {
105             perror("sendto");
106             exit(EXIT_FAILURE);
107         }
108     }
109 
110     char buffer[42] = {0};
111     int recv_count = 0;
112     // 接受最多100条或3秒超时
113     struct timeval recv_start_time;
114     gettimeofday(&recv_start_time, NULL);
115     while (recv_count++ < 100 && recv(sock_server, buffer, sizeof(buffer), 0))
116     {
117         if ((((buffer[12]) << 8) + buffer[13]) != ETH_P_ARP)
118             continue;
119         struct timeval now_time;
120         gettimeofday(&now_time, NULL);
121         if (now_time.tv_sec - recv_start_time.tv_sec > 2)
122             break;
123         char arp_rsp_mac[18] = {0};
124         char arp_rsp_ip[18] = {0};
125         sprintf(arp_rsp_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buffer[22], buffer[23], buffer[24], buffer[25], buffer[26], buffer[27]);
126         sprintf(arp_rsp_ip, "%d.%d.%d.%d", buffer[28], buffer[29], buffer[30], buffer[31]);
127         // printf("%s %s\n", arp_rsp_mac, arp_rsp_ip);
128         if (strcmp(arp_rsp_ip, dst_ip) == 0)
129         {
130             printf("%s", arp_rsp_mac);
131             return 0;
132         }
133     }
134 
135     return 0;
136 }
137 
138 int get_mac(const char *if_name, char *mac)
139 {
140     int fd, rtn;
141     struct ifreq ifr;
142 
143     if (!if_name || !mac)
144     {
145         return -1;
146     }
147     fd = socket(AF_INET, SOCK_DGRAM, 0);
148     if (fd < 0)
149     {
150         perror("socket");
151         return -1;
152     }
153     ifr.ifr_addr.sa_family = AF_INET;
154     strncpy(ifr.ifr_name, (const char *)if_name, IFNAMSIZ - 1);
155 
156     if ((rtn = ioctl(fd, SIOCGIFHWADDR, &ifr)) == 0)
157         memcpy(mac, (unsigned char *)ifr.ifr_hwaddr.sa_data, 6);
158     close(fd);
159     return rtn;
160 }
161 
162 int get_ifidx(const char *if_name, int *idx)
163 {
164     int fd, rtn;
165     struct ifreq ifr;
166 
167     if (!if_name || !idx)
168     {
169         return -1;
170     }
171     fd = socket(AF_INET, SOCK_DGRAM, 0);
172     if (fd < 0)
173     {
174         perror("socket");
175         return -1;
176     }
177     ifr.ifr_addr.sa_family = AF_INET;
178     strncpy(ifr.ifr_name, (const char *)if_name, IFNAMSIZ - 1);
179 
180     if ((rtn = ioctl(fd, SIOCGIFINDEX, &ifr)) == 0)
181         *idx = ifr.ifr_ifindex;
182     close(fd);
183     return rtn;
184 }

  代码并不复杂,大家注意看71-90行,构造了ARP Probe数据封包。这个数据包就是向局域网广播,闻讯特定IP是否被使用。

  数据封包发送之后,我们就等待其他主机的响应。如果被使用了,则会命中130行代码。

 

  这个代码不仅可以在手动设置IP之前探测该IP是否被使用,也能在主机正常工作途中实时探测有没有其他设备设置了与我们冲突的IP。

  linux下使用原始套接字需要root权限哦。

 

  最后修改时间 2022-09-28 19:27:37

标签:ifr,int,IP,0x00,char,mac,冲突,linux,include
From: https://www.cnblogs.com/Johness/p/ip-dup-detect-in-linux.html

相关文章

  • Linux make编译
    安装问题linux编译流程linux开发部分一般来说著名的linux系统基本上分两大类:RedHat系列:Redhat、Centos、Fedora等Debian系列:Debian、Ubuntu等RedHat系列常见的......
  • Linux下Docker方式在线安装Jenkins容器
    一、Docker在线安装https://www.cnblogs.com/dabao150114/p/16739213.html二、portainer容器在线安装https://www.cnblogs.com/dabao150114/p/16739217.html三、安装Je......
  • Linux下Jenkins离线安装(war包)
    1、下载Jenkins.war包地址:https://mirrors.jenkins.io/war-stable/2.346.3/2、将Jenkins.war包上传到/usr/local/tomcat/webapps3、浏览器访问:http://192.168.150.128......
  • Linux下Gitlab服务器(docker安装)
    一、Docker在线安装https://www.cnblogs.com/dabao150114/p/16739213.html二、portainer容器在线安装https://www.cnblogs.com/dabao150114/p/16739217.html三、GitLab......
  • Linux下Docker在线安装
    Docker在线安装1、安装Docker(1).安装yum-utils软件包(提供yum-config-manager实用程序)[root@localhost]#sudoyuminstall-yyum-utils(2).设置稳定的存储......
  • Linux下docker可视化portainer容器在线安装
    portainer容器在线安装注释:portainer为docker的可视化页面,安装后可以打开,进行可视化操作.1、搜索portainer镜像[root@localhost]#dockersearchportainer2......
  • 使用Openfeign远程调用时参数为MultipartFile的使用注意事项
    摘要我们在使用openfeign进行远程调用时如果使用到参数为MultipartFile的情况时会有一些些许的差别注意事项//1.@RequestPart替换@RequestParam//2.consumes=MediaTy......
  • Qt 5.4.2 Linux环境搭建
    1)访问官方网站:http://www.qt.io/download-open-source/2)选择离线安装包3)选择合适的安装包下载(32位或64位)我这里选择的是 Qt5.4.2forLinux32-bit(535MB),​​以......
  • Linux定时任务详解
    crond定时任务详解crond是Linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,可以在无需人工干预的情况下运行作业。我的环境是3A服务器搭建centos7.9,延......
  • Linux定时任务详解
    crond定时任务详解crond是Linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,可以在无需人工干预的情况下运行作业。我的环境是3A服务器搭建centos7.......