netlink_arp.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /* NHRP netlink/neighbor table arpd code
  2. * Copyright (c) 2014-2016 Timo Teräs
  3. *
  4. * This file is free software: you may copy, redistribute and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <fcntl.h>
  10. #include <net/if.h>
  11. #include <netinet/if_ether.h>
  12. #include <linux/netlink.h>
  13. #include <linux/neighbour.h>
  14. #include <linux/netfilter/nfnetlink_log.h>
  15. #include "thread.h"
  16. #include "nhrpd.h"
  17. #include "netlink.h"
  18. #include "znl.h"
  19. int netlink_req_fd = -1;
  20. int netlink_nflog_group;
  21. static int netlink_log_fd = -1;
  22. static struct thread *netlink_log_thread;
  23. static int netlink_listen_fd = -1;
  24. typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb);
  25. void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma)
  26. {
  27. struct nlmsghdr *n;
  28. struct ndmsg *ndm;
  29. struct zbuf *zb = zbuf_alloc(512);
  30. n = znl_nlmsg_push(zb, nbma ? RTM_NEWNEIGH : RTM_DELNEIGH, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
  31. ndm = znl_push(zb, sizeof(*ndm));
  32. *ndm = (struct ndmsg) {
  33. .ndm_family = sockunion_family(proto),
  34. .ndm_ifindex = ifp->ifindex,
  35. .ndm_type = RTN_UNICAST,
  36. .ndm_state = nbma ? NUD_REACHABLE : NUD_FAILED,
  37. };
  38. znl_rta_push(zb, NDA_DST, sockunion_get_addr(proto), family2addrsize(sockunion_family(proto)));
  39. if (nbma)
  40. znl_rta_push(zb, NDA_LLADDR, sockunion_get_addr(nbma), family2addrsize(sockunion_family(nbma)));
  41. znl_nlmsg_complete(zb, n);
  42. zbuf_send(zb, netlink_req_fd);
  43. zbuf_recv(zb, netlink_req_fd);
  44. zbuf_free(zb);
  45. }
  46. static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb)
  47. {
  48. struct ndmsg *ndm;
  49. struct rtattr *rta;
  50. struct nhrp_cache *c;
  51. struct interface *ifp;
  52. struct zbuf payload;
  53. union sockunion addr;
  54. size_t len;
  55. char buf[SU_ADDRSTRLEN];
  56. int state;
  57. ndm = znl_pull(zb, sizeof(*ndm));
  58. if (!ndm) return;
  59. sockunion_family(&addr) = AF_UNSPEC;
  60. while ((rta = znl_rta_pull(zb, &payload)) != NULL) {
  61. len = zbuf_used(&payload);
  62. switch (rta->rta_type) {
  63. case NDA_DST:
  64. sockunion_set(&addr, ndm->ndm_family, zbuf_pulln(&payload, len), len);
  65. break;
  66. }
  67. }
  68. ifp = if_lookup_by_index(ndm->ndm_ifindex);
  69. if (!ifp || sockunion_family(&addr) == AF_UNSPEC)
  70. return;
  71. c = nhrp_cache_get(ifp, &addr, 0);
  72. if (!c)
  73. return;
  74. if (msg->nlmsg_type == RTM_GETNEIGH) {
  75. debugf(NHRP_DEBUG_KERNEL, "Netlink: who-has %s dev %s",
  76. sockunion2str(&addr, buf, sizeof buf),
  77. ifp->name);
  78. if (c->cur.type >= NHRP_CACHE_CACHED) {
  79. nhrp_cache_set_used(c, 1);
  80. netlink_update_binding(ifp, &addr, &c->cur.peer->vc->remote.nbma);
  81. }
  82. } else {
  83. debugf(NHRP_DEBUG_KERNEL, "Netlink: update %s dev %s nud %x",
  84. sockunion2str(&addr, buf, sizeof buf),
  85. ifp->name, ndm->ndm_state);
  86. state = (msg->nlmsg_type == RTM_NEWNEIGH) ? ndm->ndm_state : NUD_FAILED;
  87. nhrp_cache_set_used(c, state == NUD_REACHABLE);
  88. }
  89. }
  90. static int netlink_route_recv(struct thread *t)
  91. {
  92. uint8_t buf[ZNL_BUFFER_SIZE];
  93. int fd = THREAD_FD(t);
  94. struct zbuf payload, zb;
  95. struct nlmsghdr *n;
  96. zbuf_init(&zb, buf, sizeof(buf), 0);
  97. while (zbuf_recv(&zb, fd) > 0) {
  98. while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) {
  99. debugf(NHRP_DEBUG_KERNEL, "Netlink: Received msg_type %u, msg_flags %u",
  100. n->nlmsg_type, n->nlmsg_flags);
  101. switch (n->nlmsg_type) {
  102. case RTM_GETNEIGH:
  103. case RTM_NEWNEIGH:
  104. case RTM_DELNEIGH:
  105. netlink_neigh_msg(n, &payload);
  106. break;
  107. }
  108. }
  109. }
  110. thread_add_read(master, netlink_route_recv, 0, fd);
  111. return 0;
  112. }
  113. static void netlink_log_register(int fd, int group)
  114. {
  115. struct nlmsghdr *n;
  116. struct nfgenmsg *nf;
  117. struct nfulnl_msg_config_cmd cmd;
  118. struct zbuf *zb = zbuf_alloc(512);
  119. n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG<<8) | NFULNL_MSG_CONFIG, NLM_F_REQUEST | NLM_F_ACK);
  120. nf = znl_push(zb, sizeof(*nf));
  121. *nf = (struct nfgenmsg) {
  122. .nfgen_family = AF_UNSPEC,
  123. .version = NFNETLINK_V0,
  124. .res_id = htons(group),
  125. };
  126. cmd.command = NFULNL_CFG_CMD_BIND;
  127. znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd));
  128. znl_nlmsg_complete(zb, n);
  129. zbuf_send(zb, fd);
  130. zbuf_free(zb);
  131. }
  132. static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb)
  133. {
  134. struct nfgenmsg *nf;
  135. struct rtattr *rta;
  136. struct zbuf rtapl, pktpl;
  137. struct interface *ifp;
  138. struct nfulnl_msg_packet_hdr *pkthdr = NULL;
  139. uint32_t *in_ndx = NULL;
  140. nf = znl_pull(zb, sizeof(*nf));
  141. if (!nf) return;
  142. memset(&pktpl, 0, sizeof(pktpl));
  143. while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) {
  144. switch (rta->rta_type) {
  145. case NFULA_PACKET_HDR:
  146. pkthdr = znl_pull(&rtapl, sizeof(*pkthdr));
  147. break;
  148. case NFULA_IFINDEX_INDEV:
  149. in_ndx = znl_pull(&rtapl, sizeof(*in_ndx));
  150. break;
  151. case NFULA_PAYLOAD:
  152. pktpl = rtapl;
  153. break;
  154. /* NFULA_HWHDR exists and is supposed to contain source
  155. * hardware address. However, for ip_gre it seems to be
  156. * the nexthop destination address if the packet matches
  157. * route. */
  158. }
  159. }
  160. if (!pkthdr || !in_ndx || !zbuf_used(&pktpl))
  161. return;
  162. ifp = if_lookup_by_index(htonl(*in_ndx));
  163. if (!ifp)
  164. return;
  165. nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl);
  166. }
  167. static int netlink_log_recv(struct thread *t)
  168. {
  169. uint8_t buf[ZNL_BUFFER_SIZE];
  170. int fd = THREAD_FD(t);
  171. struct zbuf payload, zb;
  172. struct nlmsghdr *n;
  173. netlink_log_thread = NULL;
  174. zbuf_init(&zb, buf, sizeof(buf), 0);
  175. while (zbuf_recv(&zb, fd) > 0) {
  176. while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) {
  177. debugf(NHRP_DEBUG_KERNEL, "Netlink-log: Received msg_type %u, msg_flags %u",
  178. n->nlmsg_type, n->nlmsg_flags);
  179. switch (n->nlmsg_type) {
  180. case (NFNL_SUBSYS_ULOG<<8) | NFULNL_MSG_PACKET:
  181. netlink_log_indication(n, &payload);
  182. break;
  183. }
  184. }
  185. }
  186. THREAD_READ_ON(master, netlink_log_thread, netlink_log_recv, 0, netlink_log_fd);
  187. return 0;
  188. }
  189. void netlink_set_nflog_group(int nlgroup)
  190. {
  191. if (netlink_log_fd >= 0) {
  192. THREAD_OFF(netlink_log_thread);
  193. close(netlink_log_fd);
  194. netlink_log_fd = -1;
  195. }
  196. netlink_nflog_group = nlgroup;
  197. if (nlgroup) {
  198. netlink_log_fd = znl_open(NETLINK_NETFILTER, 0);
  199. netlink_log_register(netlink_log_fd, nlgroup);
  200. THREAD_READ_ON(master, netlink_log_thread, netlink_log_recv, 0, netlink_log_fd);
  201. }
  202. }
  203. int netlink_init(void)
  204. {
  205. netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
  206. netlink_listen_fd = znl_open(NETLINK_ROUTE, RTMGRP_NEIGH);
  207. thread_add_read(master, netlink_route_recv, 0, netlink_listen_fd);
  208. return 0;
  209. }
  210. int netlink_configure_arp(unsigned int ifindex, int pf)
  211. {
  212. struct nlmsghdr *n;
  213. struct ndtmsg *ndtm;
  214. struct rtattr *rta;
  215. struct zbuf *zb = zbuf_alloc(512);
  216. int r;
  217. n = znl_nlmsg_push(zb, RTM_SETNEIGHTBL, NLM_F_REQUEST | NLM_F_REPLACE);
  218. ndtm = znl_push(zb, sizeof(*ndtm));
  219. *ndtm = (struct ndtmsg) {
  220. .ndtm_family = pf,
  221. };
  222. znl_rta_push(zb, NDTA_NAME, pf == AF_INET ? "arp_cache" : "ndisc_cache", 10);
  223. rta = znl_rta_nested_push(zb, NDTA_PARMS);
  224. znl_rta_push_u32(zb, NDTPA_IFINDEX, ifindex);
  225. znl_rta_push_u32(zb, NDTPA_APP_PROBES, 1);
  226. znl_rta_push_u32(zb, NDTPA_MCAST_PROBES, 0);
  227. znl_rta_push_u32(zb, NDTPA_UCAST_PROBES, 0);
  228. znl_rta_nested_complete(zb, rta);
  229. znl_nlmsg_complete(zb, n);
  230. r = zbuf_send(zb, netlink_req_fd);
  231. zbuf_recv(zb, netlink_req_fd);
  232. zbuf_free(zb);
  233. return r;
  234. }