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