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