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