1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
4 * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
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 <netlink-private/netlink.h>
59 #include <netlink/netlink.h>
60 #include <netlink/netfilter/nfnl.h>
61
62 #include <linux/netfilter/nfnetlink.h>
63
64 /**
65 * @name Socket Creating
66 * @{
67 */
68
69 /**
70 * Create and connect netfilter netlink socket.
71 * @arg sk Netlink socket.
72 *
73 * Creates a NETLINK_NETFILTER netlink socket, binds the socket and
74 * issues a connection attempt.
75 *
76 * @see nl_connect()
77 *
78 * @return 0 on success or a negative error code.
79 */
nfnl_connect(struct nl_sock * sk)80 int nfnl_connect(struct nl_sock *sk)
81 {
82 return nl_connect(sk, NETLINK_NETFILTER);
83 }
84
85 /** @} */
86
87 /**
88 * @name Sending
89 * @{
90 */
91
92 /**
93 * Send trivial netfilter netlink message
94 * @arg sk Netlink socket.
95 * @arg subsys_id nfnetlink subsystem
96 * @arg type nfnetlink message type
97 * @arg flags message flags
98 * @arg family nfnetlink address family
99 * @arg res_id nfnetlink resource id
100 *
101 * @return 0 on success or a negative error code. Due to a bug, this function
102 * returns the number of bytes sent. Treat any non-negative number as success.
103 */
nfnl_send_simple(struct nl_sock * sk,uint8_t subsys_id,uint8_t type,int flags,uint8_t family,uint16_t res_id)104 int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type,
105 int flags, uint8_t family, uint16_t res_id)
106 {
107 struct nfgenmsg hdr = {
108 .nfgen_family = family,
109 .version = NFNETLINK_V0,
110 .res_id = htons(res_id),
111 };
112
113 return nl_send_simple(sk, NFNLMSG_TYPE(subsys_id, type), flags,
114 &hdr, sizeof(hdr));
115 }
116
117 /** @} */
118
119 /**
120 * @name Message Parsing
121 * @{
122 */
123
124 /**
125 * Get netfilter subsystem id from message
126 * @arg nlh netlink messsage header
127 */
nfnlmsg_subsys(struct nlmsghdr * nlh)128 uint8_t nfnlmsg_subsys(struct nlmsghdr *nlh)
129 {
130 return NFNL_SUBSYS_ID(nlh->nlmsg_type);
131 }
132
133 /**
134 * Get netfilter message type from message
135 * @arg nlh netlink messsage header
136 */
nfnlmsg_subtype(struct nlmsghdr * nlh)137 uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh)
138 {
139 return NFNL_MSG_TYPE(nlh->nlmsg_type);
140 }
141
142 /**
143 * Get netfilter family from message
144 * @arg nlh netlink messsage header
145 */
nfnlmsg_family(struct nlmsghdr * nlh)146 uint8_t nfnlmsg_family(struct nlmsghdr *nlh)
147 {
148 struct nfgenmsg *nfg = nlmsg_data(nlh);
149
150 return nfg->nfgen_family;
151 }
152
153 /**
154 * Get netfilter resource id from message
155 * @arg nlh netlink messsage header
156 */
nfnlmsg_res_id(struct nlmsghdr * nlh)157 uint16_t nfnlmsg_res_id(struct nlmsghdr *nlh)
158 {
159 struct nfgenmsg *nfg = nlmsg_data(nlh);
160
161 return ntohs(nfg->res_id);
162 }
163
164 /** @} */
165
166 /**
167 * @name Message Building
168 * @{
169 */
170
nfnlmsg_append(struct nl_msg * msg,uint8_t family,uint16_t res_id)171 static int nfnlmsg_append(struct nl_msg *msg, uint8_t family, uint16_t res_id)
172 {
173 struct nfgenmsg *nfg;
174
175 nfg = nlmsg_reserve(msg, sizeof(*nfg), NLMSG_ALIGNTO);
176 if (nfg == NULL)
177 return -NLE_NOMEM;
178
179 nfg->nfgen_family = family;
180 nfg->version = NFNETLINK_V0;
181 nfg->res_id = htons(res_id);
182 NL_DBG(2, "msg %p: Added nfnetlink header family=%d res_id=%d\n",
183 msg, family, res_id);
184 return 0;
185 }
186
187 /**
188 * Allocate a new netfilter netlink message
189 * @arg subsys_id nfnetlink subsystem
190 * @arg type nfnetlink message type
191 * @arg flags message flags
192 * @arg family nfnetlink address family
193 * @arg res_id nfnetlink resource id
194 *
195 * @return Newly allocated netlink message or NULL.
196 */
nfnlmsg_alloc_simple(uint8_t subsys_id,uint8_t type,int flags,uint8_t family,uint16_t res_id)197 struct nl_msg *nfnlmsg_alloc_simple(uint8_t subsys_id, uint8_t type, int flags,
198 uint8_t family, uint16_t res_id)
199 {
200 struct nl_msg *msg;
201
202 msg = nlmsg_alloc_simple(NFNLMSG_TYPE(subsys_id, type), flags);
203 if (msg == NULL)
204 return NULL;
205
206 if (nfnlmsg_append(msg, family, res_id) < 0)
207 goto nla_put_failure;
208
209 return msg;
210
211 nla_put_failure:
212 nlmsg_free(msg);
213 return NULL;
214 }
215
216 /**
217 * Add netlink and netfilter netlink headers to netlink message
218 * @arg msg netlink message
219 * @arg pid netlink process id
220 * @arg seq sequence number of message
221 * @arg subsys_id nfnetlink subsystem
222 * @arg type nfnetlink message type
223 * @arg flags message flags
224 * @arg family nfnetlink address family
225 * @arg res_id nfnetlink resource id
226 */
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)227 int nfnlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq,
228 uint8_t subsys_id, uint8_t type, int flags, uint8_t family,
229 uint16_t res_id)
230 {
231 struct nlmsghdr *nlh;
232
233 nlh = nlmsg_put(msg, pid, seq, NFNLMSG_TYPE(subsys_id, type), 0, flags);
234 if (nlh == NULL)
235 return -NLE_MSGSIZE;
236
237 return nfnlmsg_append(msg, family, res_id);
238 }
239
240 /** @} */
241
242 /** @} */
243