libipq.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. /*
  2. * libipq.c
  3. *
  4. * IPQ userspace library.
  5. *
  6. * Please note that this library is still developmental, and there may
  7. * be some API changes.
  8. *
  9. * Author: James Morris <jmorris@intercode.com.au>
  10. *
  11. * 07-11-2001 Modified by Fernando Anton to add support for IPv6.
  12. *
  13. * Copyright (c) 2000-2001 Netfilter Core Team
  14. *
  15. * This program is free software; you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation; either version 2 of the License, or
  18. * (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. */
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <sys/time.h>
  31. #include <sys/types.h>
  32. #include <libipq/libipq.h>
  33. #include <netinet/in.h>
  34. #include <linux/netfilter.h>
  35. /****************************************************************************
  36. *
  37. * Private interface
  38. *
  39. ****************************************************************************/
  40. enum {
  41. IPQ_ERR_NONE = 0,
  42. IPQ_ERR_IMPL,
  43. IPQ_ERR_HANDLE,
  44. IPQ_ERR_SOCKET,
  45. IPQ_ERR_BIND,
  46. IPQ_ERR_BUFFER,
  47. IPQ_ERR_RECV,
  48. IPQ_ERR_NLEOF,
  49. IPQ_ERR_ADDRLEN,
  50. IPQ_ERR_STRUNC,
  51. IPQ_ERR_RTRUNC,
  52. IPQ_ERR_NLRECV,
  53. IPQ_ERR_SEND,
  54. IPQ_ERR_SUPP,
  55. IPQ_ERR_RECVBUF,
  56. IPQ_ERR_TIMEOUT,
  57. IPQ_ERR_PROTOCOL
  58. };
  59. #define IPQ_MAXERR IPQ_ERR_PROTOCOL
  60. struct ipq_errmap_t {
  61. int errcode;
  62. char *message;
  63. } ipq_errmap[] = {
  64. { IPQ_ERR_NONE, "Unknown error" },
  65. { IPQ_ERR_IMPL, "Implementation error" },
  66. { IPQ_ERR_HANDLE, "Unable to create netlink handle" },
  67. { IPQ_ERR_SOCKET, "Unable to create netlink socket" },
  68. { IPQ_ERR_BIND, "Unable to bind netlink socket" },
  69. { IPQ_ERR_BUFFER, "Unable to allocate buffer" },
  70. { IPQ_ERR_RECV, "Failed to receive netlink message" },
  71. { IPQ_ERR_NLEOF, "Received EOF on netlink socket" },
  72. { IPQ_ERR_ADDRLEN, "Invalid peer address length" },
  73. { IPQ_ERR_STRUNC, "Sent message truncated" },
  74. { IPQ_ERR_RTRUNC, "Received message truncated" },
  75. { IPQ_ERR_NLRECV, "Received error from netlink" },
  76. { IPQ_ERR_SEND, "Failed to send netlink message" },
  77. { IPQ_ERR_SUPP, "Operation not supported" },
  78. { IPQ_ERR_RECVBUF, "Receive buffer size invalid" },
  79. { IPQ_ERR_TIMEOUT, "Timeout"},
  80. { IPQ_ERR_PROTOCOL, "Invalid protocol specified" }
  81. };
  82. static int ipq_errno = IPQ_ERR_NONE;
  83. static ssize_t ipq_netlink_sendto(const struct ipq_handle *h,
  84. const void *msg, size_t len);
  85. static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h,
  86. unsigned char *buf, size_t len,
  87. int timeout);
  88. static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h,
  89. const struct msghdr *msg,
  90. unsigned int flags);
  91. static char *ipq_strerror(int errcode);
  92. static ssize_t ipq_netlink_sendto(const struct ipq_handle *h,
  93. const void *msg, size_t len)
  94. {
  95. int status = sendto(h->fd, msg, len, 0,
  96. (struct sockaddr *)&h->peer, sizeof(h->peer));
  97. if (status < 0)
  98. ipq_errno = IPQ_ERR_SEND;
  99. return status;
  100. }
  101. static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h,
  102. const struct msghdr *msg,
  103. unsigned int flags)
  104. {
  105. int status = sendmsg(h->fd, msg, flags);
  106. if (status < 0)
  107. ipq_errno = IPQ_ERR_SEND;
  108. return status;
  109. }
  110. static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h,
  111. unsigned char *buf, size_t len,
  112. int timeout)
  113. {
  114. unsigned int addrlen;
  115. int status;
  116. struct nlmsghdr *nlh;
  117. if (len < sizeof(struct nlmsgerr)) {
  118. ipq_errno = IPQ_ERR_RECVBUF;
  119. return -1;
  120. }
  121. addrlen = sizeof(h->peer);
  122. if (timeout != 0) {
  123. int ret;
  124. struct timeval tv;
  125. fd_set read_fds;
  126. if (timeout < 0) {
  127. /* non-block non-timeout */
  128. tv.tv_sec = 0;
  129. tv.tv_usec = 0;
  130. } else {
  131. tv.tv_sec = timeout / 1000000;
  132. tv.tv_usec = timeout % 1000000;
  133. }
  134. FD_ZERO(&read_fds);
  135. FD_SET(h->fd, &read_fds);
  136. ret = select(h->fd+1, &read_fds, NULL, NULL, &tv);
  137. if (ret < 0) {
  138. if (errno == EINTR) {
  139. return 0;
  140. } else {
  141. ipq_errno = IPQ_ERR_RECV;
  142. return -1;
  143. }
  144. }
  145. if (!FD_ISSET(h->fd, &read_fds)) {
  146. ipq_errno = IPQ_ERR_TIMEOUT;
  147. return 0;
  148. }
  149. }
  150. status = recvfrom(h->fd, buf, len, 0,
  151. (struct sockaddr *)&h->peer, &addrlen);
  152. if (status < 0) {
  153. ipq_errno = IPQ_ERR_RECV;
  154. return status;
  155. }
  156. if (addrlen != sizeof(h->peer)) {
  157. ipq_errno = IPQ_ERR_RECV;
  158. return -1;
  159. }
  160. if (h->peer.nl_pid != 0) {
  161. ipq_errno = IPQ_ERR_RECV;
  162. return -1;
  163. }
  164. if (status == 0) {
  165. ipq_errno = IPQ_ERR_NLEOF;
  166. return -1;
  167. }
  168. nlh = (struct nlmsghdr *)buf;
  169. if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) {
  170. ipq_errno = IPQ_ERR_RTRUNC;
  171. return -1;
  172. }
  173. return status;
  174. }
  175. static char *ipq_strerror(int errcode)
  176. {
  177. if (errcode < 0 || errcode > IPQ_MAXERR)
  178. errcode = IPQ_ERR_IMPL;
  179. return ipq_errmap[errcode].message;
  180. }
  181. /****************************************************************************
  182. *
  183. * Public interface
  184. *
  185. ****************************************************************************/
  186. /*
  187. * Create and initialise an ipq handle.
  188. */
  189. struct ipq_handle *ipq_create_handle(uint32_t flags, uint32_t protocol)
  190. {
  191. int status;
  192. struct ipq_handle *h;
  193. h = (struct ipq_handle *)malloc(sizeof(struct ipq_handle));
  194. if (h == NULL) {
  195. ipq_errno = IPQ_ERR_HANDLE;
  196. return NULL;
  197. }
  198. memset(h, 0, sizeof(struct ipq_handle));
  199. if (protocol == NFPROTO_IPV4)
  200. h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);
  201. else if (protocol == NFPROTO_IPV6)
  202. h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_IP6_FW);
  203. else {
  204. ipq_errno = IPQ_ERR_PROTOCOL;
  205. free(h);
  206. return NULL;
  207. }
  208. if (h->fd == -1) {
  209. ipq_errno = IPQ_ERR_SOCKET;
  210. free(h);
  211. return NULL;
  212. }
  213. memset(&h->local, 0, sizeof(struct sockaddr_nl));
  214. h->local.nl_family = AF_NETLINK;
  215. h->local.nl_pid = getpid();
  216. h->local.nl_groups = 0;
  217. status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local));
  218. if (status == -1) {
  219. ipq_errno = IPQ_ERR_BIND;
  220. close(h->fd);
  221. free(h);
  222. return NULL;
  223. }
  224. memset(&h->peer, 0, sizeof(struct sockaddr_nl));
  225. h->peer.nl_family = AF_NETLINK;
  226. h->peer.nl_pid = 0;
  227. h->peer.nl_groups = 0;
  228. return h;
  229. }
  230. /*
  231. * No error condition is checked here at this stage, but it may happen
  232. * if/when reliable messaging is implemented.
  233. */
  234. int ipq_destroy_handle(struct ipq_handle *h)
  235. {
  236. if (h) {
  237. close(h->fd);
  238. free(h);
  239. }
  240. return 0;
  241. }
  242. int ipq_set_mode(const struct ipq_handle *h,
  243. uint8_t mode, size_t range)
  244. {
  245. struct {
  246. struct nlmsghdr nlh;
  247. ipq_peer_msg_t pm;
  248. } req;
  249. memset(&req, 0, sizeof(req));
  250. req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req));
  251. req.nlh.nlmsg_flags = NLM_F_REQUEST;
  252. req.nlh.nlmsg_type = IPQM_MODE;
  253. req.nlh.nlmsg_pid = h->local.nl_pid;
  254. req.pm.msg.mode.value = mode;
  255. req.pm.msg.mode.range = range;
  256. return ipq_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
  257. }
  258. /*
  259. * timeout is in microseconds (1 second is 1000000 (1 million) microseconds)
  260. *
  261. */
  262. ssize_t ipq_read(const struct ipq_handle *h,
  263. unsigned char *buf, size_t len, int timeout)
  264. {
  265. return ipq_netlink_recvfrom(h, buf, len, timeout);
  266. }
  267. int ipq_message_type(const unsigned char *buf)
  268. {
  269. return ((struct nlmsghdr*)buf)->nlmsg_type;
  270. }
  271. int ipq_get_msgerr(const unsigned char *buf)
  272. {
  273. struct nlmsghdr *h = (struct nlmsghdr *)buf;
  274. struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
  275. return -err->error;
  276. }
  277. ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf)
  278. {
  279. return NLMSG_DATA((struct nlmsghdr *)(buf));
  280. }
  281. int ipq_set_verdict(const struct ipq_handle *h,
  282. ipq_id_t id,
  283. unsigned int verdict,
  284. size_t data_len,
  285. unsigned char *buf)
  286. {
  287. unsigned char nvecs;
  288. size_t tlen;
  289. struct nlmsghdr nlh;
  290. ipq_peer_msg_t pm;
  291. struct iovec iov[3];
  292. struct msghdr msg;
  293. memset(&nlh, 0, sizeof(nlh));
  294. nlh.nlmsg_flags = NLM_F_REQUEST;
  295. nlh.nlmsg_type = IPQM_VERDICT;
  296. nlh.nlmsg_pid = h->local.nl_pid;
  297. memset(&pm, 0, sizeof(pm));
  298. pm.msg.verdict.value = verdict;
  299. pm.msg.verdict.id = id;
  300. pm.msg.verdict.data_len = data_len;
  301. iov[0].iov_base = &nlh;
  302. iov[0].iov_len = sizeof(nlh);
  303. iov[1].iov_base = &pm;
  304. iov[1].iov_len = sizeof(pm);
  305. tlen = sizeof(nlh) + sizeof(pm);
  306. nvecs = 2;
  307. if (data_len && buf) {
  308. iov[2].iov_base = buf;
  309. iov[2].iov_len = data_len;
  310. tlen += data_len;
  311. nvecs++;
  312. }
  313. msg.msg_name = (void *)&h->peer;
  314. msg.msg_namelen = sizeof(h->peer);
  315. msg.msg_iov = iov;
  316. msg.msg_iovlen = nvecs;
  317. msg.msg_control = NULL;
  318. msg.msg_controllen = 0;
  319. msg.msg_flags = 0;
  320. nlh.nlmsg_len = tlen;
  321. return ipq_netlink_sendmsg(h, &msg, 0);
  322. }
  323. /* Not implemented yet */
  324. int ipq_ctl(const struct ipq_handle *h, int request, ...)
  325. {
  326. return 1;
  327. }
  328. char *ipq_errstr(void)
  329. {
  330. return ipq_strerror(ipq_errno);
  331. }
  332. void ipq_perror(const char *s)
  333. {
  334. if (s)
  335. fputs(s, stderr);
  336. else
  337. fputs("ERROR", stderr);
  338. if (ipq_errno)
  339. fprintf(stderr, ": %s", ipq_errstr());
  340. if (errno)
  341. fprintf(stderr, ": %s", strerror(errno));
  342. fputc('\n', stderr);
  343. }