netlink_helpers.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /* Taken & modified from iproute2's libnetlink.c
  3. * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  4. */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <time.h>
  10. #include <sys/socket.h>
  11. #include "netlink_helpers.h"
  12. static int rcvbuf = 1024 * 1024;
  13. void rtnl_close(struct rtnl_handle *rth)
  14. {
  15. if (rth->fd >= 0) {
  16. close(rth->fd);
  17. rth->fd = -1;
  18. }
  19. }
  20. int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
  21. int protocol)
  22. {
  23. socklen_t addr_len;
  24. int sndbuf = 32768;
  25. int one = 1;
  26. memset(rth, 0, sizeof(*rth));
  27. rth->proto = protocol;
  28. rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
  29. if (rth->fd < 0) {
  30. perror("Cannot open netlink socket");
  31. return -1;
  32. }
  33. if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF,
  34. &sndbuf, sizeof(sndbuf)) < 0) {
  35. perror("SO_SNDBUF");
  36. goto err;
  37. }
  38. if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF,
  39. &rcvbuf, sizeof(rcvbuf)) < 0) {
  40. perror("SO_RCVBUF");
  41. goto err;
  42. }
  43. /* Older kernels may no support extended ACK reporting */
  44. setsockopt(rth->fd, SOL_NETLINK, NETLINK_EXT_ACK,
  45. &one, sizeof(one));
  46. memset(&rth->local, 0, sizeof(rth->local));
  47. rth->local.nl_family = AF_NETLINK;
  48. rth->local.nl_groups = subscriptions;
  49. if (bind(rth->fd, (struct sockaddr *)&rth->local,
  50. sizeof(rth->local)) < 0) {
  51. perror("Cannot bind netlink socket");
  52. goto err;
  53. }
  54. addr_len = sizeof(rth->local);
  55. if (getsockname(rth->fd, (struct sockaddr *)&rth->local,
  56. &addr_len) < 0) {
  57. perror("Cannot getsockname");
  58. goto err;
  59. }
  60. if (addr_len != sizeof(rth->local)) {
  61. fprintf(stderr, "Wrong address length %d\n", addr_len);
  62. goto err;
  63. }
  64. if (rth->local.nl_family != AF_NETLINK) {
  65. fprintf(stderr, "Wrong address family %d\n",
  66. rth->local.nl_family);
  67. goto err;
  68. }
  69. rth->seq = time(NULL);
  70. return 0;
  71. err:
  72. rtnl_close(rth);
  73. return -1;
  74. }
  75. int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
  76. {
  77. return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
  78. }
  79. static int __rtnl_recvmsg(int fd, struct msghdr *msg, int flags)
  80. {
  81. int len;
  82. do {
  83. len = recvmsg(fd, msg, flags);
  84. } while (len < 0 && (errno == EINTR || errno == EAGAIN));
  85. if (len < 0) {
  86. fprintf(stderr, "netlink receive error %s (%d)\n",
  87. strerror(errno), errno);
  88. return -errno;
  89. }
  90. if (len == 0) {
  91. fprintf(stderr, "EOF on netlink\n");
  92. return -ENODATA;
  93. }
  94. return len;
  95. }
  96. static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
  97. {
  98. struct iovec *iov = msg->msg_iov;
  99. char *buf;
  100. int len;
  101. iov->iov_base = NULL;
  102. iov->iov_len = 0;
  103. len = __rtnl_recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC);
  104. if (len < 0)
  105. return len;
  106. if (len < 32768)
  107. len = 32768;
  108. buf = malloc(len);
  109. if (!buf) {
  110. fprintf(stderr, "malloc error: not enough buffer\n");
  111. return -ENOMEM;
  112. }
  113. iov->iov_base = buf;
  114. iov->iov_len = len;
  115. len = __rtnl_recvmsg(fd, msg, 0);
  116. if (len < 0) {
  117. free(buf);
  118. return len;
  119. }
  120. if (answer)
  121. *answer = buf;
  122. else
  123. free(buf);
  124. return len;
  125. }
  126. static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
  127. nl_ext_ack_fn_t errfn)
  128. {
  129. fprintf(stderr, "RTNETLINK answers: %s\n",
  130. strerror(-err->error));
  131. }
  132. static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iov,
  133. size_t iovlen, struct nlmsghdr **answer,
  134. bool show_rtnl_err, nl_ext_ack_fn_t errfn)
  135. {
  136. struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
  137. struct iovec riov;
  138. struct msghdr msg = {
  139. .msg_name = &nladdr,
  140. .msg_namelen = sizeof(nladdr),
  141. .msg_iov = iov,
  142. .msg_iovlen = iovlen,
  143. };
  144. unsigned int seq = 0;
  145. struct nlmsghdr *h;
  146. int i, status;
  147. char *buf;
  148. for (i = 0; i < iovlen; i++) {
  149. h = iov[i].iov_base;
  150. h->nlmsg_seq = seq = ++rtnl->seq;
  151. if (answer == NULL)
  152. h->nlmsg_flags |= NLM_F_ACK;
  153. }
  154. status = sendmsg(rtnl->fd, &msg, 0);
  155. if (status < 0) {
  156. perror("Cannot talk to rtnetlink");
  157. return -1;
  158. }
  159. /* change msg to use the response iov */
  160. msg.msg_iov = &riov;
  161. msg.msg_iovlen = 1;
  162. i = 0;
  163. while (1) {
  164. next:
  165. status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
  166. ++i;
  167. if (status < 0)
  168. return status;
  169. if (msg.msg_namelen != sizeof(nladdr)) {
  170. fprintf(stderr,
  171. "Sender address length == %d!\n",
  172. msg.msg_namelen);
  173. exit(1);
  174. }
  175. for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
  176. int len = h->nlmsg_len;
  177. int l = len - sizeof(*h);
  178. if (l < 0 || len > status) {
  179. if (msg.msg_flags & MSG_TRUNC) {
  180. fprintf(stderr, "Truncated message!\n");
  181. free(buf);
  182. return -1;
  183. }
  184. fprintf(stderr,
  185. "Malformed message: len=%d!\n",
  186. len);
  187. exit(1);
  188. }
  189. if (nladdr.nl_pid != 0 ||
  190. h->nlmsg_pid != rtnl->local.nl_pid ||
  191. h->nlmsg_seq > seq || h->nlmsg_seq < seq - iovlen) {
  192. /* Don't forget to skip that message. */
  193. status -= NLMSG_ALIGN(len);
  194. h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
  195. continue;
  196. }
  197. if (h->nlmsg_type == NLMSG_ERROR) {
  198. struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
  199. int error = err->error;
  200. if (l < sizeof(struct nlmsgerr)) {
  201. fprintf(stderr, "ERROR truncated\n");
  202. free(buf);
  203. return -1;
  204. }
  205. if (error) {
  206. errno = -error;
  207. if (rtnl->proto != NETLINK_SOCK_DIAG &&
  208. show_rtnl_err)
  209. rtnl_talk_error(h, err, errfn);
  210. }
  211. if (i < iovlen) {
  212. free(buf);
  213. goto next;
  214. }
  215. if (error) {
  216. free(buf);
  217. return -i;
  218. }
  219. if (answer)
  220. *answer = (struct nlmsghdr *)buf;
  221. else
  222. free(buf);
  223. return 0;
  224. }
  225. if (answer) {
  226. *answer = (struct nlmsghdr *)buf;
  227. return 0;
  228. }
  229. fprintf(stderr, "Unexpected reply!\n");
  230. status -= NLMSG_ALIGN(len);
  231. h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
  232. }
  233. free(buf);
  234. if (msg.msg_flags & MSG_TRUNC) {
  235. fprintf(stderr, "Message truncated!\n");
  236. continue;
  237. }
  238. if (status) {
  239. fprintf(stderr, "Remnant of size %d!\n", status);
  240. exit(1);
  241. }
  242. }
  243. }
  244. static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
  245. struct nlmsghdr **answer, bool show_rtnl_err,
  246. nl_ext_ack_fn_t errfn)
  247. {
  248. struct iovec iov = {
  249. .iov_base = n,
  250. .iov_len = n->nlmsg_len,
  251. };
  252. return __rtnl_talk_iov(rtnl, &iov, 1, answer, show_rtnl_err, errfn);
  253. }
  254. int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
  255. struct nlmsghdr **answer)
  256. {
  257. return __rtnl_talk(rtnl, n, answer, true, NULL);
  258. }
  259. int addattr(struct nlmsghdr *n, int maxlen, int type)
  260. {
  261. return addattr_l(n, maxlen, type, NULL, 0);
  262. }
  263. int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
  264. {
  265. return addattr_l(n, maxlen, type, &data, sizeof(__u8));
  266. }
  267. int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
  268. {
  269. return addattr_l(n, maxlen, type, &data, sizeof(__u16));
  270. }
  271. int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
  272. {
  273. return addattr_l(n, maxlen, type, &data, sizeof(__u32));
  274. }
  275. int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
  276. {
  277. return addattr_l(n, maxlen, type, &data, sizeof(__u64));
  278. }
  279. int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
  280. {
  281. return addattr_l(n, maxlen, type, str, strlen(str)+1);
  282. }
  283. int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
  284. int alen)
  285. {
  286. int len = RTA_LENGTH(alen);
  287. struct rtattr *rta;
  288. if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
  289. fprintf(stderr, "%s: Message exceeded bound of %d\n",
  290. __func__, maxlen);
  291. return -1;
  292. }
  293. rta = NLMSG_TAIL(n);
  294. rta->rta_type = type;
  295. rta->rta_len = len;
  296. if (alen)
  297. memcpy(RTA_DATA(rta), data, alen);
  298. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
  299. return 0;
  300. }
  301. int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
  302. {
  303. if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
  304. fprintf(stderr, "%s: Message exceeded bound of %d\n",
  305. __func__, maxlen);
  306. return -1;
  307. }
  308. memcpy(NLMSG_TAIL(n), data, len);
  309. memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
  310. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
  311. return 0;
  312. }
  313. struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
  314. {
  315. struct rtattr *nest = NLMSG_TAIL(n);
  316. addattr_l(n, maxlen, type, NULL, 0);
  317. return nest;
  318. }
  319. int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
  320. {
  321. nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
  322. return n->nlmsg_len;
  323. }