/src/get_gateway.c

https://gitlab.com/biometricscurious/zmap · C · 237 lines · 195 code · 26 blank · 16 comment · 41 complexity · 807d2389e039ceeb901d9441e834af94 MD5 · raw file

  1. /*
  2. * ZMap Copyright 2013 Regents of the University of Michigan
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy
  6. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include <errno.h>
  13. #include <assert.h>
  14. #include <netinet/in.h>
  15. #include <net/if.h>
  16. #include <sys/socket.h>
  17. #include <sys/ioctl.h>
  18. #include <linux/netlink.h>
  19. #include <linux/rtnetlink.h>
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <arpa/inet.h>
  23. #include "../lib/logger.h"
  24. int read_nl_sock(int sock, char *buf, int buf_len)
  25. {
  26. int msg_len = 0;
  27. char *pbuf = buf;
  28. do {
  29. int len = recv(sock, pbuf, buf_len - msg_len, 0);
  30. if (len <= 0) {
  31. log_debug("get-gw", "recv failed: %s", strerror(errno));
  32. return -1;
  33. }
  34. struct nlmsghdr *nlhdr = (struct nlmsghdr *)pbuf;
  35. if (NLMSG_OK(nlhdr, ((unsigned int)len)) == 0 ||
  36. nlhdr->nlmsg_type == NLMSG_ERROR) {
  37. log_debug("get-gw", "recv failed: %s", strerror(errno));
  38. return -1;
  39. }
  40. if (nlhdr->nlmsg_type == NLMSG_DONE) {
  41. break;
  42. } else {
  43. msg_len += len;
  44. pbuf += len;
  45. }
  46. if ((nlhdr->nlmsg_flags & NLM_F_MULTI) == 0) {
  47. break;
  48. }
  49. } while (1);
  50. return msg_len;
  51. }
  52. int send_nl_req(uint16_t msg_type, uint32_t seq,
  53. void *payload, uint32_t payload_len)
  54. {
  55. int sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
  56. if (sock < 0) {
  57. log_error("get-gw", "unable to get socket: %s", strerror(errno));
  58. return -1;
  59. }
  60. if (NLMSG_SPACE(payload_len) < payload_len) {
  61. // Integer overflow
  62. return -1;
  63. }
  64. struct nlmsghdr *nlmsg;
  65. nlmsg = malloc(NLMSG_SPACE(payload_len));
  66. if (!nlmsg) {
  67. return -1;
  68. }
  69. memset(nlmsg, 0, sizeof(nlmsg));
  70. memcpy(NLMSG_DATA(nlmsg), payload, payload_len);
  71. nlmsg->nlmsg_type = msg_type;
  72. nlmsg->nlmsg_len = NLMSG_LENGTH(payload_len);
  73. nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
  74. nlmsg->nlmsg_seq = seq;
  75. nlmsg->nlmsg_pid = getpid();
  76. if (send(sock, nlmsg, nlmsg->nlmsg_len, 0) < 0) {
  77. log_error("get-gw", "failure sending: %s", strerror(errno));
  78. return -1;
  79. }
  80. free(nlmsg);
  81. return sock;
  82. }
  83. int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac)
  84. {
  85. char buf[8192];
  86. struct ndmsg req;
  87. struct nlmsghdr *nlhdr;
  88. if (!gw_ip || !hw_mac) {
  89. return -1;
  90. }
  91. // Send RTM_GETNEIGH request
  92. req.ndm_family = AF_INET;
  93. req.ndm_ifindex = if_nametoindex(iface);
  94. req.ndm_state = NUD_REACHABLE;
  95. req.ndm_type = NDA_LLADDR;
  96. int sock = send_nl_req(RTM_GETNEIGH, 1, &req, sizeof(req));
  97. // Read responses
  98. unsigned nl_len = read_nl_sock(sock, buf, sizeof(buf));
  99. if (nl_len <= 0) {
  100. return -1;
  101. }
  102. // Parse responses
  103. nlhdr = (struct nlmsghdr *)buf;
  104. while (NLMSG_OK(nlhdr, nl_len)) {
  105. struct rtattr *rt_attr;
  106. struct rtmsg *rt_msg;
  107. int rt_len;
  108. unsigned char mac[6];
  109. struct in_addr dst_ip;
  110. int correct_ip = 0;
  111. rt_msg = (struct rtmsg *) NLMSG_DATA(nlhdr);
  112. if ((rt_msg->rtm_family != AF_INET)) {
  113. return -1;
  114. }
  115. rt_attr = (struct rtattr *) RTM_RTA(rt_msg);
  116. rt_len = RTM_PAYLOAD(nlhdr);
  117. while (RTA_OK(rt_attr, rt_len)) {
  118. switch (rt_attr->rta_type) {
  119. case NDA_LLADDR:
  120. assert(RTA_PAYLOAD(rt_attr) == IFHWADDRLEN);
  121. memcpy(mac, RTA_DATA(rt_attr), IFHWADDRLEN);
  122. break;
  123. case NDA_DST:
  124. assert(RTA_PAYLOAD(rt_attr) == sizeof(dst_ip));
  125. memcpy(&dst_ip, RTA_DATA(rt_attr), sizeof(dst_ip));
  126. if (memcmp(&dst_ip, gw_ip, sizeof(dst_ip)) == 0) {
  127. correct_ip = 1;
  128. }
  129. break;
  130. }
  131. rt_attr = RTA_NEXT(rt_attr, rt_len);
  132. }
  133. if (correct_ip) {
  134. memcpy(hw_mac, mac, IFHWADDRLEN);
  135. return 0;
  136. }
  137. nlhdr = NLMSG_NEXT(nlhdr, nl_len);
  138. }
  139. return -1;
  140. }
  141. // gw and iface[IF_NAMESIZE] MUST be allocated
  142. int get_default_gw(struct in_addr *gw, char *iface)
  143. {
  144. struct rtmsg req;
  145. unsigned int nl_len;
  146. char buf[8192];
  147. struct nlmsghdr *nlhdr;
  148. if (!gw || !iface) {
  149. return -1;
  150. }
  151. // Send RTM_GETROUTE request
  152. memset(&req, 0, sizeof(req));
  153. int sock = send_nl_req(RTM_GETROUTE, 0, &req, sizeof(req));
  154. // Read responses
  155. nl_len = read_nl_sock(sock, buf, sizeof(buf));
  156. if (nl_len <= 0) {
  157. return -1;
  158. }
  159. // Parse responses
  160. nlhdr = (struct nlmsghdr *)buf;
  161. while (NLMSG_OK(nlhdr, nl_len)) {
  162. struct rtattr *rt_attr;
  163. struct rtmsg *rt_msg;
  164. int rt_len;
  165. int has_gw = 0;
  166. rt_msg = (struct rtmsg *) NLMSG_DATA(nlhdr);
  167. if ((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN)) {
  168. return -1;
  169. }
  170. rt_attr = (struct rtattr *) RTM_RTA(rt_msg);
  171. rt_len = RTM_PAYLOAD(nlhdr);
  172. while (RTA_OK(rt_attr, rt_len)) {
  173. switch (rt_attr->rta_type) {
  174. case RTA_OIF:
  175. if_indextoname(*(int *) RTA_DATA(rt_attr), iface);
  176. break;
  177. case RTA_GATEWAY:
  178. gw->s_addr = *(unsigned int *) RTA_DATA(rt_attr);
  179. has_gw = 1;
  180. break;
  181. }
  182. rt_attr = RTA_NEXT(rt_attr, rt_len);
  183. }
  184. if (has_gw) {
  185. return 0;
  186. }
  187. nlhdr = NLMSG_NEXT(nlhdr, nl_len);
  188. }
  189. return -1;
  190. }
  191. // Returns the first IP address for a given iface
  192. int get_iface_ip(char *iface, struct in_addr *ip)
  193. {
  194. int sock;
  195. struct ifreq ifr;
  196. sock = socket(AF_INET, SOCK_DGRAM, 0);
  197. if (sock < 0) {
  198. log_error("get-gw", "failure opening socket: %s", strerror(errno));
  199. return -1;
  200. }
  201. ifr.ifr_addr.sa_family = AF_INET;
  202. strncpy(ifr.ifr_name, iface, IFNAMSIZ-1);
  203. if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) {
  204. log_error("get-gw", "ioctl failure: %s", strerror(errno));
  205. close(sock);
  206. return -1;
  207. }
  208. close(sock);
  209. memcpy(ip, &((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr, sizeof(*ip));
  210. return 0;
  211. }