• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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