You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

456 lines
10KB

  1. #include "netutils.h"
  2. #include <errno.h>
  3. #include <ieee80211.h>
  4. #include <log.h>
  5. #include <string.h>
  6. #ifndef __APPLE__
  7. #include <unistd.h>
  8. #include <netlink/netlink.h>
  9. #include <netlink/genl/genl.h>
  10. #include <netlink/genl/ctrl.h>
  11. #include <netlink/route/link.h>
  12. #include <netlink/route/neighbour.h>
  13. #include <netlink/errno.h>
  14. #include <linux/nl80211.h>
  15. struct nlroute_state {
  16. struct nl_sock *socket;
  17. };
  18. static struct nlroute_state nlroute_state;
  19. static int nlroute_init(struct nlroute_state *state) {
  20. state->socket = nl_socket_alloc();
  21. if (!state->socket) {
  22. log_error("Failed to allocate netlink socket.");
  23. return -ENOMEM;
  24. }
  25. if (nl_connect(state->socket, NETLINK_ROUTE)) {
  26. log_error("Failed to connect to generic netlink.");
  27. nl_socket_free(state->socket);
  28. return -ENOLINK;
  29. }
  30. return 0;
  31. }
  32. static void nlroute_free(struct nlroute_state *state) {
  33. nl_socket_free(state->socket);
  34. }
  35. struct nl80211_state {
  36. struct nl_sock *socket;
  37. int nl80211_id;
  38. };
  39. static struct nl80211_state nl80211_state;
  40. static int nl80211_init(struct nl80211_state *state) {
  41. state->socket = nl_socket_alloc();
  42. if (!state->socket) {
  43. log_error("Failed to allocate netlink socket.");
  44. return -ENOMEM;
  45. }
  46. nl_socket_set_buffer_size(state->socket, 8192, 8192);
  47. if (genl_connect(state->socket)) {
  48. log_error("Failed to connect to generic netlink.");
  49. nl_socket_free(state->socket);
  50. return -ENOLINK;
  51. }
  52. state->nl80211_id = genl_ctrl_resolve(state->socket, "nl80211");
  53. if (state->nl80211_id < 0) {
  54. log_error("nl80211 not found.");
  55. nl_socket_free(state->socket);
  56. return -ENOENT;
  57. }
  58. return 0;
  59. }
  60. static void nl80211_free(struct nl80211_state *state) {
  61. nl_socket_free(state->socket);
  62. }
  63. int netutils_init() {
  64. int err;
  65. err = nlroute_init(&nlroute_state);
  66. if (err < 0)
  67. return err;
  68. err = nl80211_init(&nl80211_state);
  69. if (err < 0)
  70. return err;
  71. return 0;
  72. }
  73. void netutils_cleanup() {
  74. nlroute_free(&nlroute_state);
  75. nl80211_free(&nl80211_state);
  76. }
  77. int neighbor_add(int ifindex, const struct ether_addr *eth, const struct in6_addr *in6) {
  78. int err;
  79. struct rtnl_neigh *neigh;
  80. struct nl_addr *nl_ipaddr, *nl_llcaddr;
  81. neigh = rtnl_neigh_alloc();
  82. if (!neigh) {
  83. log_error("Could not allocate netlink message");
  84. err = -ENOMEM;
  85. goto out;
  86. }
  87. rtnl_neigh_set_ifindex(neigh, ifindex);
  88. nl_ipaddr = nl_addr_build(AF_INET6, (void *) in6, sizeof(struct in6_addr));
  89. if (!nl_ipaddr) {
  90. log_error("Could not allocate netlink message");
  91. err = -ENOMEM;
  92. goto out;
  93. }
  94. rtnl_neigh_set_dst(neigh, nl_ipaddr);
  95. nl_llcaddr = nl_addr_build(AF_LLC, (void *) eth, sizeof(struct ether_addr));
  96. if (!nl_llcaddr) {
  97. log_error("Could not allocate netlink message");
  98. err = -ENOMEM;
  99. goto out;
  100. }
  101. rtnl_neigh_set_lladdr(neigh, nl_llcaddr);
  102. rtnl_neigh_set_state(neigh, NUD_PERMANENT);
  103. err = rtnl_neigh_add(nlroute_state.socket, neigh, NLM_F_CREATE);
  104. if (err < 0) {
  105. log_error("Could not add neighbor: %s", nl_geterror(err));
  106. }
  107. out:
  108. if (neigh)
  109. rtnl_neigh_put(neigh);
  110. if (nl_ipaddr)
  111. nl_addr_put(nl_ipaddr);
  112. if (nl_llcaddr)
  113. nl_addr_put(nl_llcaddr);
  114. return err;
  115. }
  116. int neighbor_remove(int ifindex, const struct in6_addr *in6) {
  117. int err;
  118. struct rtnl_neigh *neigh;
  119. struct nl_addr *nl_ipaddr;
  120. neigh = rtnl_neigh_alloc();
  121. if (!neigh) {
  122. log_error("Could not allocate netlink message");
  123. err = -ENOMEM;
  124. goto out;
  125. }
  126. rtnl_neigh_set_ifindex(neigh, ifindex);
  127. nl_ipaddr = nl_addr_build(AF_INET6, (void *) in6, sizeof(struct in6_addr));
  128. if (!nl_ipaddr) {
  129. log_error("Could not allocate netlink message");
  130. err = -ENOMEM;
  131. goto out;
  132. }
  133. rtnl_neigh_set_dst(neigh, nl_ipaddr);
  134. err = rtnl_neigh_delete(nlroute_state.socket, neigh, 0);
  135. if (err < 0) {
  136. log_error("Could not delete neighbor: %s", nl_geterror(err));
  137. }
  138. out:
  139. if (neigh)
  140. rtnl_neigh_put(neigh);
  141. if (nl_ipaddr)
  142. nl_addr_put(nl_ipaddr);
  143. return err;
  144. }
  145. int set_monitor_mode(int ifindex) {
  146. int err = 0;
  147. struct nl_msg *m = NULL;
  148. struct nl_msg *flags = NULL;
  149. m = nlmsg_alloc();
  150. if (!m) {
  151. log_error("Could not allocate netlink message");
  152. err = -ENOMEM;
  153. goto out;
  154. }
  155. genlmsg_put(m, 0, 0, nl80211_state.nl80211_id, 0, 0, NL80211_CMD_SET_INTERFACE, 0);
  156. NLA_PUT_U32(m, NL80211_ATTR_IFINDEX, ifindex);
  157. NLA_PUT_U32(m, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
  158. flags = nlmsg_alloc();
  159. if (!flags) {
  160. log_error("Could not allocate netlink message");
  161. err = -ENOMEM;
  162. goto out;
  163. }
  164. NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_ACTIVE);
  165. nla_put_nested(m, NL80211_ATTR_MNTR_FLAGS, flags);
  166. nlmsg_free(flags);
  167. flags = 0;
  168. err = nl_send_auto(nl80211_state.socket, m);
  169. if (err < 0) {
  170. log_error("Error while sending via netlink: %s", nl_geterror(err));
  171. goto out;
  172. }
  173. err = nl_recvmsgs_default(nl80211_state.socket);
  174. if (err < 0) {
  175. log_error("Error while receiving via netlink: %s", nl_geterror(err));
  176. goto out;
  177. }
  178. goto out;
  179. nla_put_failure:
  180. log_error("building message failed");
  181. err = -ENOBUFS;
  182. out:
  183. if (m)
  184. nlmsg_free(m);
  185. if (flags)
  186. nlmsg_free(flags);
  187. return err;
  188. }
  189. int set_channel(int ifindex, int channel /* TODO int ctrl_freq , int bw, int cntr_freq */) {
  190. int err;
  191. struct nl_msg *m;
  192. int freq;
  193. freq = ieee80211_channel_to_frequency(channel);
  194. if (!freq) {
  195. log_error("Invalid channel number %d", channel);
  196. err = -EINVAL;
  197. goto out;
  198. }
  199. m = nlmsg_alloc();
  200. if (!m) {
  201. log_error("Could not allocate netlink message");
  202. err = -ENOMEM;
  203. goto out;
  204. }
  205. if (genlmsg_put(m, 0, 0, nl80211_state.nl80211_id, 0, 0, NL80211_CMD_SET_CHANNEL, 0) == NULL) {
  206. err = -ENOBUFS;
  207. goto out;
  208. }
  209. NLA_PUT_U32(m, NL80211_ATTR_IFINDEX, ifindex);
  210. NLA_PUT_U32(m, NL80211_ATTR_WIPHY_FREQ, freq);
  211. NLA_PUT_U32(m, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
  212. err = nl_send_auto(nl80211_state.socket, m);
  213. if (err < 0) {
  214. log_error("error while sending via netlink");
  215. goto out;
  216. }
  217. err = nl_recvmsgs_default(nl80211_state.socket);
  218. goto out;
  219. nla_put_failure:
  220. log_error("building message failed");
  221. err = -ENOBUFS;
  222. out:
  223. if (m)
  224. nlmsg_free(m);
  225. return err;
  226. }
  227. static int link_updown(int ifindex, int up) {
  228. int err;
  229. struct rtnl_link *old, *req;
  230. err = rtnl_link_get_kernel(nlroute_state.socket, ifindex, NULL, &old);
  231. if (err < 0) {
  232. log_error("Could not get link: %s", nl_geterror(err));
  233. return err;
  234. }
  235. req = rtnl_link_alloc();
  236. if (up)
  237. rtnl_link_set_flags(req, rtnl_link_str2flags("up"));
  238. else
  239. rtnl_link_set_flags(req, rtnl_link_str2flags("down"));
  240. rtnl_link_change(nlroute_state.socket, old, req, 0);
  241. rtnl_link_put(old);
  242. return 0;
  243. }
  244. int link_up(int ifindex) {
  245. return link_updown(ifindex, 1);
  246. }
  247. int link_down(int ifindex) {
  248. return link_updown(ifindex, 0);
  249. }
  250. int link_ether_addr_get(const char *ifname, struct ether_addr *addr) {
  251. int err;
  252. struct rtnl_link *link;
  253. struct nl_addr *nladdr;
  254. err = rtnl_link_get_kernel(nlroute_state.socket, 0, ifname, &link);
  255. if (err < 0) {
  256. log_error("Could not get link: %s", nl_geterror(err));
  257. return err;
  258. }
  259. nladdr = rtnl_link_get_addr(link);
  260. *addr = *(struct ether_addr *) nl_addr_get_binary_addr(nladdr);
  261. return 0;
  262. }
  263. int get_hostname(char *name, size_t len) {
  264. if (gethostname(name, len) < 0)
  265. return -errno;
  266. return 0;
  267. }
  268. #else /* __APPLE__ */
  269. #include <unistd.h>
  270. #include <fcntl.h>
  271. #include <net/if.h>
  272. #include <arpa/inet.h>
  273. #include <ifaddrs.h>
  274. #include <net/if_dl.h>
  275. #include "corewlan.h"
  276. int netutils_init() {
  277. return corewlan_init();
  278. }
  279. void netutils_cleanup() {
  280. corewlan_free();
  281. }
  282. int set_monitor_mode(int ifindex) {
  283. corewlan_disassociate(ifindex);
  284. /* TODO implement here instead of using libpcap */
  285. return 0;
  286. }
  287. int set_channel(int ifindex, int channel) {
  288. return corewlan_set_channel(ifindex, channel);
  289. }
  290. int link_up(int ifindex) {
  291. (void) ifindex;
  292. return 0; /* TODO implement */
  293. }
  294. int link_down(int ifindex) {
  295. (void) ifindex;
  296. return 0; /* TODO implement */
  297. }
  298. int link_ether_addr_get(const char *ifname, struct ether_addr *addr) {
  299. struct ifaddrs *ifap, *ifa;
  300. if (getifaddrs(&ifap) < 0)
  301. return -1;
  302. for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
  303. if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_LINK) && !strcmp(ifname, ifa->ifa_name)) {
  304. struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
  305. memcpy(addr, LLADDR(sdl), sdl->sdl_alen);
  306. return 0;
  307. }
  308. }
  309. return -1;
  310. }
  311. int get_hostname(char *name, size_t len) {
  312. return corewlan_get_hostname(name, len);
  313. }
  314. /* TODO would be nicer to use PF_ROUTE socket instead of calling ndp */
  315. int neighbor_add(int ifindex, const struct ether_addr *eth, const struct in6_addr *in6) {
  316. if (fork() <= 0) {
  317. char eth_str[18];
  318. char in6_str[INET6_ADDRSTRLEN];
  319. char iface[IFNAMSIZ];
  320. char in6scope_str[INET6_ADDRSTRLEN + 1 + IFNAMSIZ];
  321. strlcpy(eth_str, ether_ntoa(eth), sizeof(eth_str));;
  322. sprintf(in6scope_str, "%s%%%s", inet_ntop(AF_INET6, (void *) in6, in6_str, sizeof(in6_str)),
  323. if_indextoname(ifindex, iface));
  324. int null = open("/dev/null", O_WRONLY);
  325. dup2(null, 1 /* stdout */);
  326. dup2(null, 2 /* stderr */);
  327. execlp("/usr/sbin/ndp", "/usr/sbin/ndp", "-sn", in6scope_str, eth_str, (char *) NULL);
  328. close(null);
  329. }
  330. return 0;
  331. }
  332. int neighbor_remove(int ifindex, const struct in6_addr *in6) {
  333. if (fork() <= 0) {
  334. char in6_str[INET6_ADDRSTRLEN];
  335. char iface[IFNAMSIZ];
  336. char in6scope_str[INET6_ADDRSTRLEN + 1 + IFNAMSIZ];
  337. sprintf(in6scope_str, "%s%%%s", inet_ntop(AF_INET6, (void *) in6, in6_str, sizeof(in6_str)),
  338. if_indextoname(ifindex, iface));
  339. int null = open("/dev/null", O_WRONLY);
  340. dup2(null, 1 /* stdout */);
  341. dup2(null, 2 /* stderr */);
  342. execlp("/usr/sbin/ndp", "/usr/sbin/ndp", "-dn", in6scope_str, (char *) NULL);
  343. close(null);
  344. }
  345. return 0;
  346. }
  347. #endif /* __APPLE__ */
  348. int neighbor_add_rfc4291(int ifindex, const struct ether_addr *addr) {
  349. struct in6_addr in6;
  350. rfc4291_addr(addr, &in6);
  351. return neighbor_add(ifindex, addr, &in6);
  352. }
  353. int neighbor_remove_rfc4291(int ifindex, const struct ether_addr *addr) {
  354. struct in6_addr in6;
  355. rfc4291_addr(addr, &in6);
  356. return neighbor_remove(ifindex, &in6);
  357. }
  358. void rfc4291_addr(const struct ether_addr *eth, struct in6_addr *in6) {
  359. memset(in6, 0, sizeof(struct in6_addr));
  360. in6->s6_addr[0] = 0xfe;
  361. in6->s6_addr[1] = 0x80;
  362. in6->s6_addr[8] = eth->ether_addr_octet[0] ^ 0x02;
  363. in6->s6_addr[9] = eth->ether_addr_octet[1];
  364. in6->s6_addr[10] = eth->ether_addr_octet[2];
  365. in6->s6_addr[11] = 0xff;
  366. in6->s6_addr[12] = 0xfe;
  367. in6->s6_addr[13] = eth->ether_addr_octet[3];
  368. in6->s6_addr[14] = eth->ether_addr_octet[4];
  369. in6->s6_addr[15] = eth->ether_addr_octet[5];
  370. }