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