1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * lib/netfilter/nfnl.c Netfilter Netlink
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-2012 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 * @defgroup nfnl Netfilter Library (libnl-nf)
17 *
18 * @par Message Format
19 * @code
20 * <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
21 * +----------------------------+- - -+- - - - - - - - - - -+- - -+
22 * | Header | Pad | Payload | Pad |
23 * | struct nlmsghdr | | | |
24 * +----------------------------+- - -+- - - - - - - - - - -+- - -+
25 * @endcode
26 * @code
27 * <-------- NFNL_HDRLEN --------->
28 * +--------------------------+- - -+------------+
29 * | Netfilter Netlink Header | Pad | Attributes |
30 * | struct nfgenmsg | | |
31 * +--------------------------+- - -+------------+
32 * nfnlmsg_attrdata(nfg, hdrlen)-----^
33 * @endcode
34 *
35 * @par 1) Creating a new netfilter netlink message
36 * @code
37 * struct nl_msg *msg;
38 *
39 * // Create a new empty netlink message
40 * msg = nlmsg_alloc();
41 *
42 * // Append the netlink and netfilter netlink message header
43 * hdr = nfnlmsg_put(msg, PID, SEQ, SUBSYS, TYPE, NLM_F_ECHO,
44 * FAMILY, RES_ID);
45 *
46 * // Append the attributes.
47 * nla_put_u32(msg, 1, 0x10);
48 *
49 * // Message is ready to be sent.
50 * nl_send_auto_complete(sk, msg);
51 *
52 * // All done? Free the message.
53 * nlmsg_free(msg);
54 * @endcode
55 *
56 * @par 2) Sending of trivial messages
57 * @code
58 * // For trivial messages not requiring any subsys specific header or
59 * // attributes, nfnl_send_simple() may be used to send messages directly.
60 * nfnl_send_simple(sk, SUBSYS, TYPE, 0, FAMILY, RES_ID);
61 * @endcode
62 * @{
63 */
64
65 #include <netlink-private/netlink.h>
66 #include <netlink/netlink.h>
67 #include <netlink/netfilter/nfnl.h>
68
69 #include <linux/netfilter/nfnetlink.h>
70
71 /**
72 * @name Socket Creating
73 * @{
74 */
75
76 /**
77 * Create and connect netfilter netlink socket.
78 * @arg sk Netlink socket.
79 *
80 * Creates a NETLINK_NETFILTER netlink socket, binds the socket and
81 * issues a connection attempt.
82 *
83 * @see nl_connect()
84 *
85 * @return 0 on success or a negative error code.
86 */
nfnl_connect(struct nl_sock * sk)87 int nfnl_connect(struct nl_sock *sk)
88 {
89 return nl_connect(sk, NETLINK_NETFILTER);
90 }
91
92 /** @} */
93
94 /**
95 * @name Sending
96 * @{
97 */
98
99 /**
100 * Send trivial netfilter netlink message
101 * @arg sk Netlink socket.
102 * @arg subsys_id nfnetlink subsystem
103 * @arg type nfnetlink message type
104 * @arg flags message flags
105 * @arg family nfnetlink address family
106 * @arg res_id nfnetlink resource id
107 *
108 * @return 0 on success or a negative error code. Due to a bug, this function
109 * returns the number of bytes sent. Treat any non-negative number as success.
110 */
nfnl_send_simple(struct nl_sock * sk,uint8_t subsys_id,uint8_t type,int flags,uint8_t family,uint16_t res_id)111 int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type,
112 int flags, uint8_t family, uint16_t res_id)
113 {
114 struct nfgenmsg hdr = {
115 .nfgen_family = family,
116 .version = NFNETLINK_V0,
117 .res_id = htons(res_id),
118 };
119
120 return nl_send_simple(sk, NFNLMSG_TYPE(subsys_id, type), flags,
121 &hdr, sizeof(hdr));
122 }
123
124 /** @} */
125
126 /**
127 * @name Message Parsing
128 * @{
129 */
130
131 /**
132 * Get netfilter subsystem id from message
133 * @arg nlh netlink messsage header
134 */
nfnlmsg_subsys(struct nlmsghdr * nlh)135 uint8_t nfnlmsg_subsys(struct nlmsghdr *nlh)
136 {
137 return NFNL_SUBSYS_ID(nlh->nlmsg_type);
138 }
139
140 /**
141 * Get netfilter message type from message
142 * @arg nlh netlink messsage header
143 */
nfnlmsg_subtype(struct nlmsghdr * nlh)144 uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh)
145 {
146 return NFNL_MSG_TYPE(nlh->nlmsg_type);
147 }
148
149 /**
150 * Get netfilter family from message
151 * @arg nlh netlink messsage header
152 */
nfnlmsg_family(struct nlmsghdr * nlh)153 uint8_t nfnlmsg_family(struct nlmsghdr *nlh)
154 {
155 struct nfgenmsg *nfg = nlmsg_data(nlh);
156
157 return nfg->nfgen_family;
158 }
159
160 /**
161 * Get netfilter resource id from message
162 * @arg nlh netlink messsage header
163 */
nfnlmsg_res_id(struct nlmsghdr * nlh)164 uint16_t nfnlmsg_res_id(struct nlmsghdr *nlh)
165 {
166 struct nfgenmsg *nfg = nlmsg_data(nlh);
167
168 return ntohs(nfg->res_id);
169 }
170
171 /** @} */
172
173 /**
174 * @name Message Building
175 * @{
176 */
177
nfnlmsg_append(struct nl_msg * msg,uint8_t family,uint16_t res_id)178 static int nfnlmsg_append(struct nl_msg *msg, uint8_t family, uint16_t res_id)
179 {
180 struct nfgenmsg *nfg;
181
182 nfg = nlmsg_reserve(msg, sizeof(*nfg), NLMSG_ALIGNTO);
183 if (nfg == NULL)
184 return -NLE_NOMEM;
185
186 nfg->nfgen_family = family;
187 nfg->version = NFNETLINK_V0;
188 nfg->res_id = htons(res_id);
189 NL_DBG(2, "msg %p: Added nfnetlink header family=%d res_id=%d\n",
190 msg, family, res_id);
191 return 0;
192 }
193
194 /**
195 * Allocate a new netfilter netlink message
196 * @arg subsys_id nfnetlink subsystem
197 * @arg type nfnetlink message type
198 * @arg flags message flags
199 * @arg family nfnetlink address family
200 * @arg res_id nfnetlink resource id
201 *
202 * @return Newly allocated netlink message or NULL.
203 */
nfnlmsg_alloc_simple(uint8_t subsys_id,uint8_t type,int flags,uint8_t family,uint16_t res_id)204 struct nl_msg *nfnlmsg_alloc_simple(uint8_t subsys_id, uint8_t type, int flags,
205 uint8_t family, uint16_t res_id)
206 {
207 struct nl_msg *msg;
208
209 msg = nlmsg_alloc_simple(NFNLMSG_TYPE(subsys_id, type), flags);
210 if (msg == NULL)
211 return NULL;
212
213 if (nfnlmsg_append(msg, family, res_id) < 0)
214 goto nla_put_failure;
215
216 return msg;
217
218 nla_put_failure:
219 nlmsg_free(msg);
220 return NULL;
221 }
222
223 /**
224 * Add netlink and netfilter netlink headers to netlink message
225 * @arg msg netlink message
226 * @arg pid netlink process id
227 * @arg seq sequence number of message
228 * @arg subsys_id nfnetlink subsystem
229 * @arg type nfnetlink message type
230 * @arg flags message flags
231 * @arg family nfnetlink address family
232 * @arg res_id nfnetlink resource id
233 */
nfnlmsg_put(struct nl_msg * msg,uint32_t pid,uint32_t seq,uint8_t subsys_id,uint8_t type,int flags,uint8_t family,uint16_t res_id)234 int nfnlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq,
235 uint8_t subsys_id, uint8_t type, int flags, uint8_t family,
236 uint16_t res_id)
237 {
238 struct nlmsghdr *nlh;
239
240 nlh = nlmsg_put(msg, pid, seq, NFNLMSG_TYPE(subsys_id, type), 0, flags);
241 if (nlh == NULL)
242 return -NLE_MSGSIZE;
243
244 return nfnlmsg_append(msg, family, res_id);
245 }
246
247 /** @} */
248
249 /** @} */
250