linux下检测ip冲突

原理其实很简单,那就是广播一个arp包,然后recv,如果没有数据(这里要设置延时),那么说明这个ip是可用的,否则就检测这个数据是否为回复我们发出的arp的应答包.如果是则证明ip已被使用,否则继续等待.

这里可以看下busybox的dhcp中的检测程序。
networking/udhcp/arpping.c

C代码
  1. /*vi:setsw=4ts=4:*/
  2. /*
  3. *arpping.c
  4. *
  5. *Mostlystolenfrom:dhcpcd-DHCPclientdaemon
  6. *byYoichiHariguchi<yoichi@fore.com>
  7. */
  8. #include<netinet/if_ether.h>
  9. #include<net/if_arp.h>
  10. #include"common.h"
  11. #include"dhcpd.h"
  12. //这里是arp包的格式,其中的数据格式都是宏了,比如uint_8_t为无符char.
  13. structarpMsg{
  14. /*Ethernetheader*/
  15. uint8_th_dest[6];/*00destinationetheraddr*/
  16. uint8_th_source[6];/*06sourceetheraddr*/
  17. uint16_th_proto;/*0cpackettypeIDfield*/
  18. /*ARPpacket*/
  19. uint16_thtype;/*0ehardwaretype(mustbeARPHRD_ETHER)*/
  20. uint16_tptype;/*10protocoltype(mustbeETH_P_IP)*/
  21. uint8_thlen;/*12hardwareaddresslength(mustbe6)*/
  22. uint8_tplen;/*13protocoladdresslength(mustbe4)*/
  23. uint16_toperation;/*14ARPopcode*/
  24. uint8_tsHaddr[6];/*16sender'shardwareaddress*/
  25. uint8_tsInaddr[4];/*1csender'sIPaddress*/
  26. uint8_ttHaddr[6];/*20target'shardwareaddress*/
  27. uint8_ttInaddr[4];/*26target'sIPaddress*/
  28. uint8_tpad[18];/*2apadformin.ethernetpayload(60bytes)*/
  29. }PACKED;
  30. enum{
  31. ARP_MSG_SIZE=0x2a
  32. };
  33. /*Returns1ifnoreplyreceived*/
  34. //主程序,如果返回1说明此ip可用
  35. intarpping(uint32_ttest_ip,uint32_tfrom_ip,uint8_t*from_mac,constchar*interface)
  36. {
  37. inttimeout_ms;
  38. //这里使用poll来检测句柄。
  39. structpollfdpfd[1];
  40. #defines(pfd[0].fd)/*socket*/
  41. intrv=1;/*"noreplyreceived"yet*/
  42. structsockaddraddr;/*forinterfacename*/
  43. structarpMsgarp;
  44. //建立scoket.由于我们是要直接访问访问链路层并自己组arp包.因此我们使用PF_PACKET协议簇.socket类型为SOCK_PACKET.
  45. s=socket(PF_PACKET,SOCK_PACKET,htons(ETH_P_ARP));
  46. if(s==-1){
  47. bb_perror_msg(bb_msg_can_not_create_raw_socket);
  48. return-1;
  49. }
  50. if(setsockopt_broadcast(s)==-1){
  51. bb_perror_msg("cannotenablebcastonrawsocket");
  52. gotoret;
  53. }
  54. //进行组包,由于是要广播,因此目的mac地址为全0.
  55. /*sendarprequest*/
  56. memset(&arp,0,sizeof(arp));
  57. memset(arp.h_dest,0xff,6);/*MACDA*/
  58. memcpy(arp.h_source,from_mac,6);/*MACSA*/
  59. arp.h_proto=htons(ETH_P_ARP);/*protocoltype(Ethernet)*/
  60. arp.htype=htons(ARPHRD_ETHER);/*hardwaretype*/
  61. arp.ptype=htons(ETH_P_IP);/*protocoltype(ARPmessage)*/
  62. arp.hlen=6;/*hardwareaddresslength*/
  63. arp.plen=4;/*protocoladdresslength*/
  64. arp.operation=htons(ARPOP_REQUEST);/*ARPopcode*/
  65. memcpy(arp.sHaddr,from_mac,6);/*sourcehardwareaddress*/
  66. memcpy(arp.sInaddr,&from_ip,sizeof(from_ip));/*sourceIPaddress*/
  67. /*tHaddriszero-fiiled*//*targethardwareaddress*/
  68. memcpy(arp.tInaddr,&test_ip,sizeof(test_ip));/*targetIPaddress*/
  69. memset(&addr,0,sizeof(addr));
  70. safe_strncpy(addr.sa_data,interface,sizeof(addr.sa_data));
  71. //广播arp包.
  72. if(sendto(s,&arp,sizeof(arp),0,&addr,sizeof(addr))<0){
  73. //TODO:errormessage?callerdidn'texpectustofail,
  74. //justreturning1"noreplyreceived"misleadsit.
  75. gotoret;
  76. }
  77. /*waitforarpreply,andcheckit*/
  78. //等待时间,超时则认为此ip地址可用
  79. timeout_ms=2000;
  80. do{
  81. intr;
  82. unsignedprevTime=monotonic_us();
  83. pfd[0].events=POLLIN;
  84. //这边他是害怕poll被信号打断,因此加了层循环,其实这边我们还可以使用ppoll的,就可以了。
  85. r=safe_poll(pfd,1,timeout_ms);
  86. if(r<0)
  87. break;
  88. if(r){
  89. //读取返回数据.
  90. r=read(s,&arp,sizeof(arp));
  91. if(r<0)
  92. break;
  93. //检测是否为应打包,发送ip是否为我们所请求的ip,这里是为了防止其他的数据包干扰我们检测。
  94. if(r>=ARP_MSG_SIZE
  95. &&arp.operation==htons(ARPOP_REPLY)
  96. /*don'tcheckit:Linuxdoesn'treturnpropertHaddr(fixedin2.6.24?)*/
  97. /*&&memcmp(arp.tHaddr,from_mac,6)==0*/
  98. &&*((uint32_t*)arp.sInaddr)==test_ip
  99. ){
  100. //说明ip地址已被使用
  101. rv=0;
  102. break;
  103. }
  104. }
  105. timeout_ms-=((unsigned)monotonic_us()-prevTime)/1000;
  106. }while(timeout_ms>0);
  107. ret:
  108. close(s);
  109. DEBUG("%srpreplyreceivedforthisaddress",rv?"Noa":"A");
  110. returnrv;
  111. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值