PageRenderTime 49ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/strongswan-5.0.0/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c

#
C | 306 lines | 219 code | 41 blank | 46 comment | 32 complexity | 7eb374f01425de356a7a5420a51703ec MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0
  1. /*
  2. * Copyright (C) 2008 Tobias Brunner
  3. * Hochschule fuer Technik Rapperswil
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. * for more details.
  14. */
  15. #include <sys/socket.h>
  16. #include <linux/netlink.h>
  17. #include <linux/rtnetlink.h>
  18. #include <errno.h>
  19. #include <unistd.h>
  20. #include "kernel_netlink_shared.h"
  21. #include <debug.h>
  22. #include <threading/mutex.h>
  23. typedef struct private_netlink_socket_t private_netlink_socket_t;
  24. /**
  25. * Private variables and functions of netlink_socket_t class.
  26. */
  27. struct private_netlink_socket_t {
  28. /**
  29. * public part of the netlink_socket_t object.
  30. */
  31. netlink_socket_t public;
  32. /**
  33. * mutex to lock access to netlink socket
  34. */
  35. mutex_t *mutex;
  36. /**
  37. * current sequence number for netlink request
  38. */
  39. int seq;
  40. /**
  41. * netlink socket protocol
  42. */
  43. int protocol;
  44. /**
  45. * netlink socket
  46. */
  47. int socket;
  48. };
  49. /**
  50. * Imported from kernel_netlink_ipsec.c
  51. */
  52. extern enum_name_t *xfrm_msg_names;
  53. METHOD(netlink_socket_t, netlink_send, status_t,
  54. private_netlink_socket_t *this, struct nlmsghdr *in, struct nlmsghdr **out,
  55. size_t *out_len)
  56. {
  57. int len, addr_len;
  58. struct sockaddr_nl addr;
  59. chunk_t result = chunk_empty, tmp;
  60. struct nlmsghdr *msg, peek;
  61. this->mutex->lock(this->mutex);
  62. in->nlmsg_seq = ++this->seq;
  63. in->nlmsg_pid = getpid();
  64. memset(&addr, 0, sizeof(addr));
  65. addr.nl_family = AF_NETLINK;
  66. addr.nl_pid = 0;
  67. addr.nl_groups = 0;
  68. if (this->protocol == NETLINK_XFRM)
  69. {
  70. chunk_t in_chunk = { (u_char*)in, in->nlmsg_len };
  71. DBG3(DBG_KNL, "sending %N: %B", xfrm_msg_names, in->nlmsg_type, &in_chunk);
  72. }
  73. while (TRUE)
  74. {
  75. len = sendto(this->socket, in, in->nlmsg_len, 0,
  76. (struct sockaddr*)&addr, sizeof(addr));
  77. if (len != in->nlmsg_len)
  78. {
  79. if (errno == EINTR)
  80. {
  81. /* interrupted, try again */
  82. continue;
  83. }
  84. this->mutex->unlock(this->mutex);
  85. DBG1(DBG_KNL, "error sending to netlink socket: %s", strerror(errno));
  86. return FAILED;
  87. }
  88. break;
  89. }
  90. while (TRUE)
  91. {
  92. char buf[4096];
  93. tmp.len = sizeof(buf);
  94. tmp.ptr = buf;
  95. msg = (struct nlmsghdr*)tmp.ptr;
  96. memset(&addr, 0, sizeof(addr));
  97. addr.nl_family = AF_NETLINK;
  98. addr.nl_pid = getpid();
  99. addr.nl_groups = 0;
  100. addr_len = sizeof(addr);
  101. len = recvfrom(this->socket, tmp.ptr, tmp.len, 0,
  102. (struct sockaddr*)&addr, &addr_len);
  103. if (len < 0)
  104. {
  105. if (errno == EINTR)
  106. {
  107. DBG1(DBG_KNL, "got interrupted");
  108. /* interrupted, try again */
  109. continue;
  110. }
  111. DBG1(DBG_KNL, "error reading from netlink socket: %s", strerror(errno));
  112. this->mutex->unlock(this->mutex);
  113. free(result.ptr);
  114. return FAILED;
  115. }
  116. if (!NLMSG_OK(msg, len))
  117. {
  118. DBG1(DBG_KNL, "received corrupted netlink message");
  119. this->mutex->unlock(this->mutex);
  120. free(result.ptr);
  121. return FAILED;
  122. }
  123. if (msg->nlmsg_seq != this->seq)
  124. {
  125. DBG1(DBG_KNL, "received invalid netlink sequence number");
  126. if (msg->nlmsg_seq < this->seq)
  127. {
  128. continue;
  129. }
  130. this->mutex->unlock(this->mutex);
  131. free(result.ptr);
  132. return FAILED;
  133. }
  134. tmp.len = len;
  135. result.ptr = realloc(result.ptr, result.len + tmp.len);
  136. memcpy(result.ptr + result.len, tmp.ptr, tmp.len);
  137. result.len += tmp.len;
  138. /* NLM_F_MULTI flag does not seem to be set correctly, we use sequence
  139. * numbers to detect multi header messages */
  140. len = recvfrom(this->socket, &peek, sizeof(peek), MSG_PEEK | MSG_DONTWAIT,
  141. (struct sockaddr*)&addr, &addr_len);
  142. if (len == sizeof(peek) && peek.nlmsg_seq == this->seq)
  143. {
  144. /* seems to be multipart */
  145. continue;
  146. }
  147. break;
  148. }
  149. *out_len = result.len;
  150. *out = (struct nlmsghdr*)result.ptr;
  151. this->mutex->unlock(this->mutex);
  152. return SUCCESS;
  153. }
  154. METHOD(netlink_socket_t, netlink_send_ack, status_t,
  155. private_netlink_socket_t *this, struct nlmsghdr *in)
  156. {
  157. struct nlmsghdr *out, *hdr;
  158. size_t len;
  159. if (netlink_send(this, in, &out, &len) != SUCCESS)
  160. {
  161. return FAILED;
  162. }
  163. hdr = out;
  164. while (NLMSG_OK(hdr, len))
  165. {
  166. switch (hdr->nlmsg_type)
  167. {
  168. case NLMSG_ERROR:
  169. {
  170. struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(hdr);
  171. if (err->error)
  172. {
  173. if (-err->error == EEXIST)
  174. { /* do not report existing routes */
  175. free(out);
  176. return ALREADY_DONE;
  177. }
  178. if (-err->error == ESRCH)
  179. { /* do not report missing entries */
  180. free(out);
  181. return NOT_FOUND;
  182. }
  183. DBG1(DBG_KNL, "received netlink error: %s (%d)",
  184. strerror(-err->error), -err->error);
  185. free(out);
  186. return FAILED;
  187. }
  188. free(out);
  189. return SUCCESS;
  190. }
  191. default:
  192. hdr = NLMSG_NEXT(hdr, len);
  193. continue;
  194. case NLMSG_DONE:
  195. break;
  196. }
  197. break;
  198. }
  199. DBG1(DBG_KNL, "netlink request not acknowledged");
  200. free(out);
  201. return FAILED;
  202. }
  203. METHOD(netlink_socket_t, destroy, void,
  204. private_netlink_socket_t *this)
  205. {
  206. if (this->socket > 0)
  207. {
  208. close(this->socket);
  209. }
  210. this->mutex->destroy(this->mutex);
  211. free(this);
  212. }
  213. /**
  214. * Described in header.
  215. */
  216. netlink_socket_t *netlink_socket_create(int protocol)
  217. {
  218. private_netlink_socket_t *this;
  219. struct sockaddr_nl addr;
  220. INIT(this,
  221. .public = {
  222. .send = _netlink_send,
  223. .send_ack = _netlink_send_ack,
  224. .destroy = _destroy,
  225. },
  226. .seq = 200,
  227. .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
  228. .protocol = protocol,
  229. );
  230. memset(&addr, 0, sizeof(addr));
  231. addr.nl_family = AF_NETLINK;
  232. this->socket = socket(AF_NETLINK, SOCK_RAW, protocol);
  233. if (this->socket < 0)
  234. {
  235. DBG1(DBG_KNL, "unable to create netlink socket");
  236. destroy(this);
  237. return NULL;
  238. }
  239. addr.nl_groups = 0;
  240. if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)))
  241. {
  242. DBG1(DBG_KNL, "unable to bind netlink socket");
  243. destroy(this);
  244. return NULL;
  245. }
  246. return &this->public;
  247. }
  248. /**
  249. * Described in header.
  250. */
  251. void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
  252. size_t buflen)
  253. {
  254. struct rtattr *rta;
  255. if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(data.len) > buflen)
  256. {
  257. DBG1(DBG_KNL, "unable to add attribute, buffer too small");
  258. return;
  259. }
  260. rta = (struct rtattr*)(((char*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len));
  261. rta->rta_type = rta_type;
  262. rta->rta_len = RTA_LENGTH(data.len);
  263. memcpy(RTA_DATA(rta), data.ptr, data.len);
  264. hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
  265. }