dhcp_snoop.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * DHCP snooping for Proxy ARP
  3. * Copyright (c) 2014, Qualcomm Atheros, Inc.
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "utils/includes.h"
  9. #include <netinet/ip.h>
  10. #include <netinet/udp.h>
  11. #include "utils/common.h"
  12. #include "l2_packet/l2_packet.h"
  13. #include "hostapd.h"
  14. #include "sta_info.h"
  15. #include "ap_drv_ops.h"
  16. #include "x_snoop.h"
  17. #include "dhcp_snoop.h"
  18. struct bootp_pkt {
  19. struct iphdr iph;
  20. struct udphdr udph;
  21. u8 op;
  22. u8 htype;
  23. u8 hlen;
  24. u8 hops;
  25. be32 xid;
  26. be16 secs;
  27. be16 flags;
  28. be32 client_ip;
  29. be32 your_ip;
  30. be32 server_ip;
  31. be32 relay_ip;
  32. u8 hw_addr[16];
  33. u8 serv_name[64];
  34. u8 boot_file[128];
  35. u8 exten[312];
  36. } STRUCT_PACKED;
  37. #define DHCPACK 5
  38. static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
  39. static const char * ipaddr_str(u32 addr)
  40. {
  41. static char buf[17];
  42. os_snprintf(buf, sizeof(buf), "%u.%u.%u.%u",
  43. (addr >> 24) & 0xff, (addr >> 16) & 0xff,
  44. (addr >> 8) & 0xff, addr & 0xff);
  45. return buf;
  46. }
  47. static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
  48. size_t len)
  49. {
  50. struct hostapd_data *hapd = ctx;
  51. const struct bootp_pkt *b;
  52. struct sta_info *sta;
  53. int exten_len;
  54. const u8 *end, *pos;
  55. int res, msgtype = 0, prefixlen = 32;
  56. u32 subnet_mask = 0;
  57. u16 tot_len;
  58. exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
  59. if (exten_len < 4)
  60. return;
  61. b = (const struct bootp_pkt *) &buf[ETH_HLEN];
  62. tot_len = ntohs(b->iph.tot_len);
  63. if (tot_len > (unsigned int) (len - ETH_HLEN))
  64. return;
  65. if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
  66. return;
  67. /* Parse DHCP options */
  68. end = (const u8 *) b + tot_len;
  69. pos = &b->exten[4];
  70. while (pos < end && *pos != 0xff) {
  71. const u8 *opt = pos++;
  72. if (*opt == 0) /* padding */
  73. continue;
  74. pos += *pos + 1;
  75. if (pos >= end)
  76. break;
  77. switch (*opt) {
  78. case 1: /* subnet mask */
  79. if (opt[1] == 4)
  80. subnet_mask = WPA_GET_BE32(&opt[2]);
  81. if (subnet_mask == 0)
  82. return;
  83. while (!(subnet_mask & 0x1)) {
  84. subnet_mask >>= 1;
  85. prefixlen--;
  86. }
  87. break;
  88. case 53: /* message type */
  89. if (opt[1])
  90. msgtype = opt[2];
  91. break;
  92. default:
  93. break;
  94. }
  95. }
  96. if (msgtype == DHCPACK) {
  97. if (b->your_ip == 0)
  98. return;
  99. /* DHCPACK for DHCPREQUEST */
  100. sta = ap_get_sta(hapd, b->hw_addr);
  101. if (!sta)
  102. return;
  103. wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
  104. " @ IPv4 address %s/%d",
  105. MAC2STR(sta->addr),
  106. ipaddr_str(be_to_host32(b->your_ip)),
  107. prefixlen);
  108. if (sta->ipaddr == b->your_ip)
  109. return;
  110. if (sta->ipaddr != 0) {
  111. wpa_printf(MSG_DEBUG,
  112. "dhcp_snoop: Removing IPv4 address %s from the ip neigh table",
  113. ipaddr_str(be_to_host32(sta->ipaddr)));
  114. hostapd_drv_br_delete_ip_neigh(hapd, 4,
  115. (u8 *) &sta->ipaddr);
  116. }
  117. res = hostapd_drv_br_add_ip_neigh(hapd, 4, (u8 *) &b->your_ip,
  118. prefixlen, sta->addr);
  119. if (res) {
  120. wpa_printf(MSG_DEBUG,
  121. "dhcp_snoop: Adding ip neigh table failed: %d",
  122. res);
  123. return;
  124. }
  125. sta->ipaddr = b->your_ip;
  126. }
  127. if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
  128. for (sta = hapd->sta_list; sta; sta = sta->next) {
  129. if (!(sta->flags & WLAN_STA_AUTHORIZED))
  130. continue;
  131. x_snoop_mcast_to_ucast_convert_send(hapd, sta,
  132. (u8 *) buf, len);
  133. }
  134. }
  135. }
  136. int dhcp_snoop_init(struct hostapd_data *hapd)
  137. {
  138. hapd->sock_dhcp = x_snoop_get_l2_packet(hapd, handle_dhcp,
  139. L2_PACKET_FILTER_DHCP);
  140. if (hapd->sock_dhcp == NULL) {
  141. wpa_printf(MSG_DEBUG,
  142. "dhcp_snoop: Failed to initialize L2 packet processing for DHCP packet: %s",
  143. strerror(errno));
  144. return -1;
  145. }
  146. return 0;
  147. }
  148. void dhcp_snoop_deinit(struct hostapd_data *hapd)
  149. {
  150. l2_packet_deinit(hapd->sock_dhcp);
  151. }