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.

libnetlink.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /*
  2. * libnetlink.c RTnetlink service routines.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version
  7. * 2 of the License, or (at your option) any later version.
  8. *
  9. * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  10. *
  11. * --
  12. *
  13. * This code has been lightly modified to adapt it in the Netsukuku source
  14. * code.
  15. */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <unistd.h>
  19. #include <syslog.h>
  20. #include <fcntl.h>
  21. #include <net/if_arp.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <string.h>
  25. #include <errno.h>
  26. #include <time.h>
  27. #include <sys/uio.h>
  28. #include <stdarg.h>
  29. #include "libnetlink.h"
  30. #include "log.h"
  31. void
  32. rtnl_close(struct rtnl_handle *rth)
  33. {
  34. close(rth->fd);
  35. }
  36. int
  37. rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
  38. int protocol)
  39. {
  40. socklen_t addr_len;
  41. int sndbuf = 32768;
  42. int rcvbuf = 32768;
  43. memset(rth, 0, sizeof(struct rtnl_handle));
  44. rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
  45. if (rth->fd < 0) {
  46. perror("Cannot open netlink socket");
  47. return -1;
  48. }
  49. if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))
  50. < 0) {
  51. perror("SO_SNDBUF");
  52. return -1;
  53. }
  54. if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))
  55. < 0) {
  56. perror("SO_RCVBUF");
  57. return -1;
  58. }
  59. memset(&rth->local, 0, sizeof(rth->local));
  60. rth->local.nl_family = AF_NETLINK;
  61. rth->local.nl_groups = subscriptions;
  62. if (bind(rth->fd, (struct sockaddr *) &rth->local, sizeof(rth->local))
  63. < 0) {
  64. perror("Cannot bind netlink socket");
  65. return -1;
  66. }
  67. addr_len = sizeof(rth->local);
  68. if (getsockname(rth->fd, (struct sockaddr *) &rth->local, &addr_len) <
  69. 0) {
  70. perror("Cannot getsockname");
  71. return -1;
  72. }
  73. if (addr_len != sizeof(rth->local)) {
  74. error("Wrong address length %d\n", addr_len);
  75. return -1;
  76. }
  77. if (rth->local.nl_family != AF_NETLINK) {
  78. error("Wrong address family %d\n", rth->local.nl_family);
  79. return -1;
  80. }
  81. rth->seq = time(NULL);
  82. return 0;
  83. }
  84. int
  85. rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
  86. {
  87. return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
  88. }
  89. int
  90. rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
  91. {
  92. struct {
  93. struct nlmsghdr nlh;
  94. struct rtgenmsg g;
  95. } req;
  96. struct sockaddr_nl nladdr;
  97. memset(&nladdr, 0, sizeof(nladdr));
  98. nladdr.nl_family = AF_NETLINK;
  99. memset(&req, 0, sizeof(req));
  100. req.nlh.nlmsg_len = sizeof(req);
  101. req.nlh.nlmsg_type = type;
  102. req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
  103. req.nlh.nlmsg_pid = 0;
  104. req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
  105. req.g.rtgen_family = family;
  106. return sendto(rth->fd, (void *) &req, sizeof(req), 0,
  107. (struct sockaddr *) &nladdr, sizeof(nladdr));
  108. }
  109. int
  110. rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
  111. {
  112. struct sockaddr_nl nladdr;
  113. memset(&nladdr, 0, sizeof(nladdr));
  114. nladdr.nl_family = AF_NETLINK;
  115. return sendto(rth->fd, buf, len, 0, (struct sockaddr *) &nladdr,
  116. sizeof(nladdr));
  117. }
  118. int
  119. rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
  120. {
  121. struct nlmsghdr nlh;
  122. struct sockaddr_nl nladdr;
  123. struct iovec iov[2] = {
  124. {.iov_base = &nlh,.iov_len = sizeof(nlh)}
  125. ,
  126. {.iov_base = req,.iov_len = len}
  127. };
  128. struct msghdr msg = {
  129. .msg_name = &nladdr,
  130. .msg_namelen = sizeof(nladdr),
  131. .msg_iov = iov,
  132. .msg_iovlen = 2,
  133. };
  134. memset(&nladdr, 0, sizeof(nladdr));
  135. nladdr.nl_family = AF_NETLINK;
  136. nlh.nlmsg_len = NLMSG_LENGTH(len);
  137. nlh.nlmsg_type = type;
  138. nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
  139. nlh.nlmsg_pid = 0;
  140. nlh.nlmsg_seq = rth->dump = ++rth->seq;
  141. return sendmsg(rth->fd, &msg, 0);
  142. }
  143. int
  144. rtnl_dump_filter(struct rtnl_handle *rth,
  145. rtnl_filter_t filter,
  146. void *arg1, rtnl_filter_t junk, void *arg2)
  147. {
  148. struct sockaddr_nl nladdr;
  149. struct iovec iov;
  150. struct msghdr msg = {
  151. .msg_name = &nladdr,
  152. .msg_namelen = sizeof(nladdr),
  153. .msg_iov = &iov,
  154. .msg_iovlen = 1,
  155. };
  156. char buf[16384];
  157. iov.iov_base = buf;
  158. while (1) {
  159. int status;
  160. struct nlmsghdr *h;
  161. iov.iov_len = sizeof(buf);
  162. status = recvmsg(rth->fd, &msg, 0);
  163. if (status < 0) {
  164. if (errno == EINTR)
  165. continue;
  166. perror("OVERRUN");
  167. continue;
  168. }
  169. if (status == 0) {
  170. error("EOF on netlink\n");
  171. return -1;
  172. }
  173. h = (struct nlmsghdr *) buf;
  174. while (NLMSG_OK(h, status)) {
  175. int err;
  176. if (nladdr.nl_pid != 0 ||
  177. h->nlmsg_pid != rth->local.nl_pid ||
  178. h->nlmsg_seq != rth->dump) {
  179. if (junk) {
  180. err = junk(&nladdr, h, arg2);
  181. if (err < 0)
  182. return err;
  183. }
  184. goto skip_it;
  185. }
  186. if (h->nlmsg_type == NLMSG_DONE)
  187. return 0;
  188. if (h->nlmsg_type == NLMSG_ERROR) {
  189. struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA(h);
  190. if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
  191. error("ERROR truncated\n");
  192. } else {
  193. errno = -err->error;
  194. perror("RTNETLINK answers");
  195. }
  196. return -1;
  197. }
  198. err = filter(&nladdr, h, arg1);
  199. if (err < 0)
  200. return err;
  201. skip_it:
  202. h = NLMSG_NEXT(h, status);
  203. }
  204. if (msg.msg_flags & MSG_TRUNC) {
  205. error("Message truncated\n");
  206. continue;
  207. }
  208. if (status) {
  209. fatal("!!!Remnant of size %d\n", status);
  210. }
  211. }
  212. }
  213. int
  214. rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
  215. unsigned groups, struct nlmsghdr *answer,
  216. rtnl_filter_t junk, void *jarg)
  217. {
  218. int status;
  219. unsigned seq;
  220. struct nlmsghdr *h;
  221. struct sockaddr_nl nladdr;
  222. struct iovec iov = {
  223. .iov_base = (void *) n,
  224. .iov_len = n->nlmsg_len
  225. };
  226. struct msghdr msg = {
  227. .msg_name = &nladdr,
  228. .msg_namelen = sizeof(nladdr),
  229. .msg_iov = &iov,
  230. .msg_iovlen = 1,
  231. };
  232. char buf[16384];
  233. memset(&nladdr, 0, sizeof(nladdr));
  234. nladdr.nl_family = AF_NETLINK;
  235. nladdr.nl_pid = peer;
  236. nladdr.nl_groups = groups;
  237. n->nlmsg_seq = seq = ++rtnl->seq;
  238. if (answer == NULL)
  239. n->nlmsg_flags |= NLM_F_ACK;
  240. status = sendmsg(rtnl->fd, &msg, 0);
  241. if (status < 0) {
  242. perror("Cannot talk to rtnetlink");
  243. return -1;
  244. }
  245. memset(buf, 0, sizeof(buf));
  246. iov.iov_base = buf;
  247. while (1) {
  248. iov.iov_len = sizeof(buf);
  249. status = recvmsg(rtnl->fd, &msg, 0);
  250. if (status < 0) {
  251. if (errno == EINTR)
  252. continue;
  253. perror("OVERRUN");
  254. continue;
  255. }
  256. if (status == 0) {
  257. error("EOF on netlink\n");
  258. return -1;
  259. }
  260. if (msg.msg_namelen != sizeof(nladdr)) {
  261. fatal("sender address length == %d\n", msg.msg_namelen);
  262. }
  263. for (h = (struct nlmsghdr *) buf; status >= sizeof(*h);) {
  264. int err;
  265. int len = h->nlmsg_len;
  266. int l = len - sizeof(*h);
  267. if (l < 0 || len > status) {
  268. if (msg.msg_flags & MSG_TRUNC) {
  269. error("Truncated message\n");
  270. return -1;
  271. }
  272. fatal("!!!malformed message: len=%d\n", len);
  273. }
  274. if (nladdr.nl_pid != peer ||
  275. h->nlmsg_pid != rtnl->local.nl_pid ||
  276. h->nlmsg_seq != seq) {
  277. if (junk) {
  278. err = junk(&nladdr, h, jarg);
  279. if (err < 0)
  280. return err;
  281. }
  282. continue;
  283. }
  284. if (h->nlmsg_type == NLMSG_ERROR) {
  285. struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA(h);
  286. if (l < sizeof(struct nlmsgerr)) {
  287. error("ERROR truncated\n");
  288. } else {
  289. errno = -err->error;
  290. if (errno == 0) {
  291. if (answer)
  292. memcpy(answer, h, h->nlmsg_len);
  293. return 0;
  294. }
  295. error("RTNETLINK answers (%d): %s", err->error,
  296. strerror(errno));
  297. }
  298. return -1;
  299. }
  300. if (answer) {
  301. memcpy(answer, h, h->nlmsg_len);
  302. return 0;
  303. }
  304. error("Unexpected reply!!!\n");
  305. status -= NLMSG_ALIGN(len);
  306. h = (struct nlmsghdr *) ((char *) h + NLMSG_ALIGN(len));
  307. }
  308. if (msg.msg_flags & MSG_TRUNC) {
  309. error("Message truncated\n");
  310. continue;
  311. }
  312. if (status)
  313. fatal("!!!Remnant of size %d\n", status);
  314. }
  315. }
  316. int
  317. rtnl_listen(struct rtnl_handle *rtnl, rtnl_filter_t handler, void *jarg)
  318. {
  319. int status;
  320. struct nlmsghdr *h;
  321. struct sockaddr_nl nladdr;
  322. struct iovec iov;
  323. struct msghdr msg = {
  324. .msg_name = &nladdr,
  325. .msg_namelen = sizeof(nladdr),
  326. .msg_iov = &iov,
  327. .msg_iovlen = 1,
  328. };
  329. char buf[8192];
  330. memset(&nladdr, 0, sizeof(nladdr));
  331. nladdr.nl_family = AF_NETLINK;
  332. nladdr.nl_pid = 0;
  333. nladdr.nl_groups = 0;
  334. iov.iov_base = buf;
  335. while (1) {
  336. iov.iov_len = sizeof(buf);
  337. status = recvmsg(rtnl->fd, &msg, 0);
  338. if (status < 0) {
  339. if (errno == EINTR)
  340. continue;
  341. perror("OVERRUN");
  342. continue;
  343. }
  344. if (status == 0) {
  345. error("EOF on netlink\n");
  346. return -1;
  347. }
  348. if (msg.msg_namelen != sizeof(nladdr)) {
  349. fatal("Sender address length == %d\n", msg.msg_namelen);
  350. }
  351. for (h = (struct nlmsghdr *) buf; status >= sizeof(*h);) {
  352. int err;
  353. int len = h->nlmsg_len;
  354. int l = len - sizeof(*h);
  355. if (l < 0 || len > status) {
  356. if (msg.msg_flags & MSG_TRUNC) {
  357. error("Truncated message\n");
  358. return -1;
  359. }
  360. fatal("!!!malformed message: len=%d\n", len);
  361. }
  362. err = handler(&nladdr, h, jarg);
  363. if (err < 0)
  364. return err;
  365. status -= NLMSG_ALIGN(len);
  366. h = (struct nlmsghdr *) ((char *) h + NLMSG_ALIGN(len));
  367. }
  368. if (msg.msg_flags & MSG_TRUNC) {
  369. error("Message truncated\n");
  370. continue;
  371. }
  372. if (status) {
  373. fatal("!!!Remnant of size %d\n", status);
  374. }
  375. }
  376. }
  377. int
  378. rtnl_from_file(FILE * rtnl, rtnl_filter_t handler, void *jarg)
  379. {
  380. int status;
  381. struct sockaddr_nl nladdr;
  382. char buf[8192];
  383. struct nlmsghdr *h = (void *) buf;
  384. memset(&nladdr, 0, sizeof(nladdr));
  385. nladdr.nl_family = AF_NETLINK;
  386. nladdr.nl_pid = 0;
  387. nladdr.nl_groups = 0;
  388. while (1) {
  389. int err, len;
  390. int l;
  391. status = fread(&buf, 1, sizeof(*h), rtnl);
  392. if (status < 0) {
  393. if (errno == EINTR)
  394. continue;
  395. perror("rtnl_from_file: fread");
  396. return -1;
  397. }
  398. if (status == 0)
  399. return 0;
  400. len = h->nlmsg_len;
  401. l = len - sizeof(*h);
  402. if (l < 0 || len > sizeof(buf)) {
  403. error("!!!malformed message: len=%d @%lu\n", len, ftell(rtnl));
  404. return -1;
  405. }
  406. status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
  407. if (status < 0) {
  408. perror("rtnl_from_file: fread");
  409. return -1;
  410. }
  411. if (status < l) {
  412. error("rtnl-from_file: truncated message\n");
  413. return -1;
  414. }
  415. err = handler(&nladdr, h, jarg);
  416. if (err < 0)
  417. return err;
  418. }
  419. }
  420. int
  421. addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data)
  422. {
  423. int len = RTA_LENGTH(4);
  424. struct rtattr *rta;
  425. if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
  426. error("addattr32: Error! max allowed bound %d exceeded\n", maxlen);
  427. return -1;
  428. }
  429. rta = NLMSG_TAIL(n);
  430. rta->rta_type = type;
  431. rta->rta_len = len;
  432. memcpy(RTA_DATA(rta), &data, 4);
  433. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
  434. return 0;
  435. }
  436. int
  437. addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
  438. int alen)
  439. {
  440. int len = RTA_LENGTH(alen);
  441. struct rtattr *rta;
  442. if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
  443. error("addattr_l ERROR: message exceeded bound of %d\n", maxlen);
  444. return -1;
  445. }
  446. rta = NLMSG_TAIL(n);
  447. rta->rta_type = type;
  448. rta->rta_len = len;
  449. memcpy(RTA_DATA(rta), data, alen);
  450. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
  451. return 0;
  452. }
  453. int
  454. addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
  455. {
  456. if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
  457. error("addraw_l ERROR: message exceeded bound of %d\n", maxlen);
  458. return -1;
  459. }
  460. memcpy(NLMSG_TAIL(n), data, len);
  461. memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
  462. n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
  463. return 0;
  464. }
  465. int
  466. rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)
  467. {
  468. int len = RTA_LENGTH(4);
  469. struct rtattr *subrta;
  470. if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
  471. error("rta_addattr32: Error! max allowed bound %d exceeded\n",
  472. maxlen);
  473. return -1;
  474. }
  475. subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN(rta->rta_len));
  476. subrta->rta_type = type;
  477. subrta->rta_len = len;
  478. memcpy(RTA_DATA(subrta), &data, 4);
  479. rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
  480. return 0;
  481. }
  482. int
  483. rta_addattr_l(struct rtattr *rta, int maxlen, int type,
  484. const void *data, int alen)
  485. {
  486. struct rtattr *subrta;
  487. int len = RTA_LENGTH(alen);
  488. if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
  489. error("rta_addattr_l: Error! max allowed bound %d exceeded\n",
  490. maxlen);
  491. return -1;
  492. }
  493. subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN(rta->rta_len));
  494. subrta->rta_type = type;
  495. subrta->rta_len = len;
  496. memcpy(RTA_DATA(subrta), data, alen);
  497. rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
  498. return 0;
  499. }
  500. int
  501. parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
  502. {
  503. memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
  504. while (RTA_OK(rta, len)) {
  505. if (rta->rta_type <= max)
  506. tb[rta->rta_type] = rta;
  507. rta = RTA_NEXT(rta, len);
  508. }
  509. if (len)
  510. error("!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
  511. return 0;
  512. }
  513. int
  514. parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta,
  515. int len)
  516. {
  517. int i = 0;
  518. memset(tb, 0, sizeof(struct rtattr *) * max);
  519. while (RTA_OK(rta, len)) {
  520. if (rta->rta_type <= max && i < max)
  521. tb[i++] = rta;
  522. rta = RTA_NEXT(rta, len);
  523. }
  524. if (len)
  525. error("!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
  526. return i;
  527. }