blob: 4f2bb5b9b9f96a1e1c8f737c8716dda1e73ef1d4 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/*
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 *
James Morrisef798b92001-05-30 00:48:03 +00009 * Author: James Morris <jmorris@intercode.com.au>
10 *
11 * Copyright (c) 2000-2001 Netfilter Core Team
12 *
Marc Bouchere6869a82000-03-20 06:03:29 +000013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 */
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <unistd.h>
Rusty Russell7e53bf92000-03-20 07:03:28 +000029
Marc Bouchere6869a82000-03-20 06:03:29 +000030#include <libipq/libipq.h>
31
32/****************************************************************************
33 *
34 * Private interface
35 *
36 ****************************************************************************/
37
38enum {
39 IPQ_ERR_NONE = 0,
40 IPQ_ERR_IMPL,
41 IPQ_ERR_HANDLE,
42 IPQ_ERR_SOCKET,
43 IPQ_ERR_BIND,
44 IPQ_ERR_BUFFER,
45 IPQ_ERR_RECV,
46 IPQ_ERR_NLEOF,
47 IPQ_ERR_ADDRLEN,
48 IPQ_ERR_STRUNC,
49 IPQ_ERR_RTRUNC,
50 IPQ_ERR_NLRECV,
51 IPQ_ERR_SEND,
52 IPQ_ERR_SUPP,
53 IPQ_ERR_RECVBUF
54};
55#define IPQ_MAXERR IPQ_ERR_RECVBUF
56
57struct ipq_errmap_t {
58 int errcode;
59 char *message;
60} ipq_errmap[] = {
61 { IPQ_ERR_NONE, "Unknown error" },
62 { IPQ_ERR_IMPL, "Implementation error" },
63 { IPQ_ERR_HANDLE, "Unable to create netlink handle" },
64 { IPQ_ERR_SOCKET, "Unable to create netlink socket" },
65 { IPQ_ERR_BIND, "Unable to bind netlink socket" },
66 { IPQ_ERR_BUFFER, "Unable to allocate buffer" },
67 { IPQ_ERR_RECV, "Failed to receive netlink message" },
68 { IPQ_ERR_NLEOF, "Received EOF on netlink socket" },
69 { IPQ_ERR_ADDRLEN, "Invalid peer address length" },
70 { IPQ_ERR_STRUNC, "Sent message truncated" },
71 { IPQ_ERR_RTRUNC, "Received message truncated" },
72 { IPQ_ERR_NLRECV, "Received error from netlink" },
73 { IPQ_ERR_SEND, "Failed to send netlink message" },
74 { IPQ_ERR_SUPP, "Operation not supported" },
75 { IPQ_ERR_RECVBUF, "Receive buffer size invalid" }
76};
77
78static int ipq_errno = IPQ_ERR_NONE;
79
80static ssize_t ipq_netlink_sendto(const struct ipq_handle *h,
81 const void *msg, size_t len);
Rusty Russell7e53bf92000-03-20 07:03:28 +000082
Marc Bouchere6869a82000-03-20 06:03:29 +000083static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h,
84 unsigned char *buf, size_t len);
Rusty Russell7e53bf92000-03-20 07:03:28 +000085
Marc Bouchere6869a82000-03-20 06:03:29 +000086static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h,
87 const struct msghdr *msg,
88 unsigned int flags);
Rusty Russell7e53bf92000-03-20 07:03:28 +000089
Marc Bouchere6869a82000-03-20 06:03:29 +000090static char *ipq_strerror(int errcode);
91
92static 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;
Rusty Russell7e53bf92000-03-20 07:03:28 +000099 return status;
Marc Bouchere6869a82000-03-20 06:03:29 +0000100}
101
102static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h,
103 const struct msghdr *msg,
104 unsigned int flags)
105{
106 int status = sendmsg(h->fd, msg, flags);
107 if (status < 0)
108 ipq_errno = IPQ_ERR_SEND;
Rusty Russell7e53bf92000-03-20 07:03:28 +0000109 return status;
Marc Bouchere6869a82000-03-20 06:03:29 +0000110}
111
112static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h,
113 unsigned char *buf, size_t len)
114{
115 int addrlen, status;
116 struct nlmsghdr *nlh;
Rusty Russell7e53bf92000-03-20 07:03:28 +0000117
Marc Bouchere6869a82000-03-20 06:03:29 +0000118 if (len < sizeof(struct nlmsgerr)) {
119 ipq_errno = IPQ_ERR_RECVBUF;
120 return -1;
121 }
122 addrlen = sizeof(h->peer);
123 status = recvfrom(h->fd, buf, len, 0,
124 (struct sockaddr *)&h->peer, &addrlen);
125 if (status < 0) {
126 ipq_errno = IPQ_ERR_RECV;
127 return status;
128 }
129 if (addrlen != sizeof(h->peer)) {
130 ipq_errno = IPQ_ERR_RECV;
131 return -1;
132 }
133 if (status == 0) {
134 ipq_errno = IPQ_ERR_NLEOF;
135 return -1;
136 }
137 nlh = (struct nlmsghdr *)buf;
138 if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) {
139 ipq_errno = IPQ_ERR_RTRUNC;
140 return -1;
141 }
142 return status;
143}
144
145static char *ipq_strerror(int errcode)
146{
147 if (errcode < 0 || errcode > IPQ_MAXERR)
148 errcode = IPQ_ERR_IMPL;
149 return ipq_errmap[errcode].message;
150}
151
152/****************************************************************************
153 *
154 * Public interface
155 *
156 ****************************************************************************/
157
Rusty Russell7e53bf92000-03-20 07:03:28 +0000158/*
Marc Bouchere6869a82000-03-20 06:03:29 +0000159 * Create and initialise an ipq handle.
160 * FIXME: implement flags.
161 */
162struct ipq_handle *ipq_create_handle(u_int32_t flags)
163{
164 int status;
165 struct ipq_handle *h;
Rusty Russell7e53bf92000-03-20 07:03:28 +0000166
Marc Bouchere6869a82000-03-20 06:03:29 +0000167 h = (struct ipq_handle *)malloc(sizeof(struct ipq_handle));
168 if (h == NULL) {
169 ipq_errno = IPQ_ERR_HANDLE;
170 return NULL;
171 }
172 memset(h, 0, sizeof(struct ipq_handle));
173 h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);
174 if (h->fd == -1) {
175 ipq_errno = IPQ_ERR_SOCKET;
176 close(h->fd);
177 free(h);
178 return NULL;
179 }
180 memset(&h->local, 0, sizeof(struct sockaddr_nl));
181 h->local.nl_family = AF_NETLINK;
182 h->local.nl_pid = getpid();
183 h->local.nl_groups = 0;
184 status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local));
185 if (status == -1) {
186 ipq_errno = IPQ_ERR_BIND;
187 close(h->fd);
188 free(h);
189 return NULL;
190 }
191 memset(&h->peer, 0, sizeof(struct sockaddr_nl));
192 h->peer.nl_family = AF_NETLINK;
193 h->peer.nl_pid = 0;
194 h->peer.nl_groups = 0;
195 return h;
196}
197
198/*
Rusty Russell7e53bf92000-03-20 07:03:28 +0000199 * No error condition is checked here at this stage, but it may happen
Marc Bouchere6869a82000-03-20 06:03:29 +0000200 * if/when reliable messaging is implemented.
201 */
202int ipq_destroy_handle(struct ipq_handle *h)
203{
204 if (h) {
205 close(h->fd);
206 free(h);
207 }
208 return 0;
209}
210
211int ipq_set_mode(const struct ipq_handle *h,
212 u_int8_t mode, size_t range)
213{
214 struct {
215 struct nlmsghdr nlh;
216 ipq_peer_msg_t pm;
217 } req;
Rusty Russell7e53bf92000-03-20 07:03:28 +0000218
Marc Bouchere6869a82000-03-20 06:03:29 +0000219 memset(&req, 0, sizeof(req));
220 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req));
221 req.nlh.nlmsg_flags = NLM_F_REQUEST;
222 req.nlh.nlmsg_type = IPQM_MODE;
223 req.nlh.nlmsg_pid = h->local.nl_pid;
224 req.pm.msg.mode.value = mode;
225 req.pm.msg.mode.range = range;
226 return ipq_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
227}
228
229/* Note: timeout is not yet implemented */
230ssize_t ipq_read(const struct ipq_handle *h,
231 unsigned char *buf, size_t len, int timeout)
232{
233 return ipq_netlink_recvfrom(h, buf, len);
234}
235
236int ipq_message_type(const unsigned char *buf)
237{
238 return ((struct nlmsghdr*)buf)->nlmsg_type;
239}
240
241int ipq_get_msgerr(const unsigned char *buf)
242{
243 struct nlmsghdr *h = (struct nlmsghdr *)buf;
244 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
245 return -err->error;
246}
247
248ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf)
249{
250 return NLMSG_DATA((struct nlmsghdr *)(buf));
251}
252
253int ipq_set_verdict(const struct ipq_handle *h,
Rusty Russell803f33c2000-09-04 05:56:10 +0000254 ipq_id_t id,
Marc Bouchere6869a82000-03-20 06:03:29 +0000255 unsigned int verdict,
256 size_t data_len,
257 unsigned char *buf)
258{
259 unsigned char nvecs;
260 size_t tlen;
261 struct nlmsghdr nlh;
262 ipq_peer_msg_t pm;
263 struct iovec iov[3];
264 struct msghdr msg;
265
266 memset(&nlh, 0, sizeof(nlh));
267 nlh.nlmsg_flags = NLM_F_REQUEST;
268 nlh.nlmsg_type = IPQM_VERDICT;
269 nlh.nlmsg_pid = h->local.nl_pid;
270 memset(&pm, 0, sizeof(pm));
271 pm.msg.verdict.value = verdict;
272 pm.msg.verdict.id = id;
273 pm.msg.verdict.data_len = data_len;
274 iov[0].iov_base = &nlh;
275 iov[0].iov_len = sizeof(nlh);
276 iov[1].iov_base = &pm;
277 iov[1].iov_len = sizeof(pm);
278 tlen = sizeof(nlh) + sizeof(pm);
279 nvecs = 2;
280 if (data_len && buf) {
281 iov[2].iov_base = buf;
282 iov[2].iov_len = data_len;
283 tlen += data_len;
284 nvecs++;
285 }
286 msg.msg_name = (void *)&h->peer;
287 msg.msg_namelen = sizeof(h->peer);
288 msg.msg_iov = iov;
289 msg.msg_iovlen = nvecs;
290 msg.msg_control = NULL;
291 msg.msg_controllen = 0;
292 msg.msg_flags = 0;
293 nlh.nlmsg_len = tlen;
294 return ipq_netlink_sendmsg(h, &msg, 0);
295}
296
297/* Not implemented yet */
298int ipq_ctl(const struct ipq_handle *h, int request, ...)
299{
300 return 1;
301}
302
James Morrisb1e0b992000-11-18 05:14:39 +0000303char *ipq_errstr(void)
304{
305 return ipq_strerror(ipq_errno);
306}
307
Marc Bouchere6869a82000-03-20 06:03:29 +0000308void ipq_perror(const char *s)
309{
310 if (s)
311 fputs(s, stderr);
312 else
313 fputs("ERROR", stderr);
314 if (ipq_errno)
James Morrisb1e0b992000-11-18 05:14:39 +0000315 fprintf(stderr, ": %s", ipq_errstr());
Marc Bouchere6869a82000-03-20 06:03:29 +0000316 if (errno)
317 fprintf(stderr, ": %s", strerror(errno));
318 fputc('\n', stderr);
319}