1 /*
2  * lib/netfilter/log.c	Netfilter Log
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
11  * Copyright (c) 2007 Secure Computing Corporation
12  */
13 
14 /**
15  * @ingroup nfnl
16  * @defgroup log Log
17  * @brief
18  * @{
19  */
20 
21 #include <sys/types.h>
22 #include <linux/netfilter/nfnetlink_log.h>
23 
24 #include <netlink-local.h>
25 #include <netlink/attr.h>
26 #include <netlink/netfilter/nfnl.h>
27 #include <netlink/netfilter/log.h>
28 
29 /**
30  * @name Log Commands
31  * @{
32  */
33 
build_log_cmd_request(uint8_t family,uint16_t queuenum,uint8_t command,struct nl_msg ** result)34 static int build_log_cmd_request(uint8_t family, uint16_t queuenum,
35 				 uint8_t command, struct nl_msg **result)
36 {
37 	struct nl_msg *msg;
38 	struct nfulnl_msg_config_cmd cmd;
39 
40 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
41 				   family, queuenum);
42 	if (msg == NULL)
43 		return -NLE_NOMEM;
44 
45 	cmd.command = command;
46 	if (nla_put(msg, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
47 		goto nla_put_failure;
48 
49 	*result = msg;
50 	return 0;
51 
52 nla_put_failure:
53 	nlmsg_free(msg);
54 	return -NLE_MSGSIZE;
55 }
56 
send_log_request(struct nl_sock * sk,struct nl_msg * msg)57 static int send_log_request(struct nl_sock *sk, struct nl_msg *msg)
58 {
59 	int err;
60 
61 	err = nl_send_auto_complete(sk, msg);
62 	nlmsg_free(msg);
63 	if (err < 0)
64 		return err;
65 
66 	return wait_for_ack(sk);
67 }
68 
nfnl_log_build_pf_bind(uint8_t pf,struct nl_msg ** result)69 int nfnl_log_build_pf_bind(uint8_t pf, struct nl_msg **result)
70 {
71 	return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_BIND, result);
72 }
73 
nfnl_log_pf_bind(struct nl_sock * nlh,uint8_t pf)74 int nfnl_log_pf_bind(struct nl_sock *nlh, uint8_t pf)
75 {
76 	struct nl_msg *msg;
77 	int err;
78 
79 	if ((err = nfnl_log_build_pf_bind(pf, &msg)) < 0)
80 		return err;
81 
82 	return send_log_request(nlh, msg);
83 }
84 
nfnl_log_build_pf_unbind(uint8_t pf,struct nl_msg ** result)85 int nfnl_log_build_pf_unbind(uint8_t pf, struct nl_msg **result)
86 {
87 	return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_UNBIND, result);
88 }
89 
nfnl_log_pf_unbind(struct nl_sock * nlh,uint8_t pf)90 int nfnl_log_pf_unbind(struct nl_sock *nlh, uint8_t pf)
91 {
92 	struct nl_msg *msg;
93 	int err;
94 
95 	if ((err = nfnl_log_build_pf_unbind(pf, &msg)) < 0)
96 		return err;
97 
98 	return send_log_request(nlh, msg);
99 }
100 
nfnl_log_build_request(const struct nfnl_log * log,struct nl_msg ** result)101 static int nfnl_log_build_request(const struct nfnl_log *log,
102 				  struct nl_msg **result)
103 {
104 	struct nl_msg *msg;
105 
106 	if (!nfnl_log_test_group(log))
107 		return -NLE_MISSING_ATTR;
108 
109 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
110 				   0, nfnl_log_get_group(log));
111 	if (msg == NULL)
112 		return -NLE_NOMEM;
113 
114 	/* This sucks. The nfnetlink_log interface always expects both
115 	 * parameters to be present. Needs to be done properly.
116 	 */
117 	if (nfnl_log_test_copy_mode(log)) {
118 		struct nfulnl_msg_config_mode mode;
119 
120 		switch (nfnl_log_get_copy_mode(log)) {
121 		case NFNL_LOG_COPY_NONE:
122 			mode.copy_mode = NFULNL_COPY_NONE;
123 			break;
124 		case NFNL_LOG_COPY_META:
125 			mode.copy_mode = NFULNL_COPY_META;
126 			break;
127 		case NFNL_LOG_COPY_PACKET:
128 			mode.copy_mode = NFULNL_COPY_PACKET;
129 			break;
130 		}
131 		mode.copy_range = htonl(nfnl_log_get_copy_range(log));
132 		mode._pad = 0;
133 
134 		if (nla_put(msg, NFULA_CFG_MODE, sizeof(mode), &mode) < 0)
135 			goto nla_put_failure;
136 	}
137 
138 	if (nfnl_log_test_flush_timeout(log) &&
139 	    nla_put_u32(msg, NFULA_CFG_TIMEOUT,
140 			htonl(nfnl_log_get_flush_timeout(log))) < 0)
141 		goto nla_put_failure;
142 
143 	if (nfnl_log_test_alloc_size(log) &&
144 	    nla_put_u32(msg, NFULA_CFG_NLBUFSIZ,
145 			htonl(nfnl_log_get_alloc_size(log))) < 0)
146 		goto nla_put_failure;
147 
148 	if (nfnl_log_test_queue_threshold(log) &&
149 	    nla_put_u32(msg, NFULA_CFG_QTHRESH,
150 			htonl(nfnl_log_get_queue_threshold(log))) < 0)
151 		goto nla_put_failure;
152 
153 	*result = msg;
154 	return 0;
155 
156 nla_put_failure:
157 	nlmsg_free(msg);
158 	return -NLE_MSGSIZE;
159 }
160 
nfnl_log_build_create_request(const struct nfnl_log * log,struct nl_msg ** result)161 int nfnl_log_build_create_request(const struct nfnl_log *log,
162 				  struct nl_msg **result)
163 {
164 	struct nfulnl_msg_config_cmd cmd;
165 	int err;
166 
167 	if ((err = nfnl_log_build_request(log, result)) < 0)
168 		return err;
169 
170 	cmd.command = NFULNL_CFG_CMD_BIND;
171 
172 	if (nla_put(*result, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
173 		goto nla_put_failure;
174 
175 	return 0;
176 
177 nla_put_failure:
178 	nlmsg_free(*result);
179 	return -NLE_MSGSIZE;
180 }
181 
nfnl_log_create(struct nl_sock * nlh,const struct nfnl_log * log)182 int nfnl_log_create(struct nl_sock *nlh, const struct nfnl_log *log)
183 {
184 	struct nl_msg *msg;
185 	int err;
186 
187 	if ((err = nfnl_log_build_create_request(log, &msg)) < 0)
188 		return err;
189 
190 	return send_log_request(nlh, msg);
191 }
192 
nfnl_log_build_change_request(const struct nfnl_log * log,struct nl_msg ** result)193 int nfnl_log_build_change_request(const struct nfnl_log *log,
194 				  struct nl_msg **result)
195 {
196 	return nfnl_log_build_request(log, result);
197 }
198 
nfnl_log_change(struct nl_sock * nlh,const struct nfnl_log * log)199 int nfnl_log_change(struct nl_sock *nlh, const struct nfnl_log *log)
200 {
201 	struct nl_msg *msg;
202 	int err;
203 
204 	if ((err = nfnl_log_build_change_request(log, &msg)) < 0)
205 		return err;
206 
207 	return send_log_request(nlh, msg);
208 }
209 
nfnl_log_build_delete_request(const struct nfnl_log * log,struct nl_msg ** result)210 int nfnl_log_build_delete_request(const struct nfnl_log *log,
211 				  struct nl_msg **result)
212 {
213 	if (!nfnl_log_test_group(log))
214 		return -NLE_MISSING_ATTR;
215 
216 	return build_log_cmd_request(0, nfnl_log_get_group(log),
217 				     NFULNL_CFG_CMD_UNBIND, result);
218 }
219 
nfnl_log_delete(struct nl_sock * nlh,const struct nfnl_log * log)220 int nfnl_log_delete(struct nl_sock *nlh, const struct nfnl_log *log)
221 {
222 	struct nl_msg *msg;
223 	int err;
224 
225 	if ((err = nfnl_log_build_delete_request(log, &msg)) < 0)
226 		return err;
227 
228 	return send_log_request(nlh, msg);
229 }
230 
231 /** @} */
232 
233 static struct nl_cache_ops nfnl_log_ops = {
234 	.co_name		= "netfilter/log",
235 	.co_obj_ops		= &log_obj_ops,
236 	.co_msgtypes		= {
237 		END_OF_MSGTYPES_LIST,
238 	},
239 };
240 
log_init(void)241 static void __init log_init(void)
242 {
243 	nl_cache_mngt_register(&nfnl_log_ops);
244 }
245 
log_exit(void)246 static void __exit log_exit(void)
247 {
248 	nl_cache_mngt_unregister(&nfnl_log_ops);
249 }
250 
251 /** @} */
252