1 /*#############################################################################
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2017 IPFire Network Development Team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
23 #include <linux/netlink.h>
24 #include <linux/nl80211.h>
25 #include <netlink/genl/ctrl.h>
26 #include <netlink/genl/genl.h>
27 #include <netlink/netlink.h>
34 #include <network/libnetwork.h>
35 #include <network/logging.h>
36 #include "libnetwork-private.h"
42 void (*log_fn
)(struct network_ctx
* ctx
,
43 int priority
, const char *file
, int line
, const char *fn
,
44 const char *format
, va_list args
);
48 struct nl_sock
* nl_socket
;
52 void network_log(struct network_ctx
* ctx
,
53 int priority
, const char* file
, int line
, const char* fn
,
54 const char* format
, ...) {
57 va_start(args
, format
);
58 ctx
->log_fn(ctx
, priority
, file
, line
, fn
, format
, args
);
62 static void log_stderr(struct network_ctx
* ctx
,
63 int priority
, const char* file
, int line
, const char* fn
,
64 const char* format
, va_list args
) {
65 fprintf(stderr
, "libnetwork: %s: ", fn
);
66 vfprintf(stderr
, format
, args
);
69 static int log_priority(const char* priority
) {
72 int prio
= strtol(priority
, &endptr
, 10);
74 if (endptr
[0] == '\0' || isspace(endptr
[0]))
77 if (strncmp(priority
, "err", 3) == 0)
80 if (strncmp(priority
, "info", 4) == 0)
83 if (strncmp(priority
, "debug", 5) == 0)
89 static int init_netlink(struct network_ctx
* ctx
) {
90 // Allocate netlink socket
91 ctx
->nl_socket
= nl_socket_alloc();
92 if (!ctx
->nl_socket
) {
93 ERROR(ctx
, "Failed to allocate netlink socket\n");
98 if (genl_connect(ctx
->nl_socket
)) {
99 ERROR(ctx
, "Failed to connect to generic netlink");
104 nl_socket_set_buffer_size(ctx
->nl_socket
, 8192, 8192);
106 // Register socket callback
107 struct nl_cb
* callback
= nl_cb_alloc(NL_CB_DEFAULT
);
109 ERROR(ctx
, "Could not allocate socket callback\n");
113 nl_socket_set_cb(ctx
->nl_socket
, callback
);
116 ctx
->nl80211_id
= genl_ctrl_resolve(ctx
->nl_socket
, "nl80211");
117 if (ctx
->nl80211_id
< 0) {
118 ERROR(ctx
, "Could not find nl80211\n");
125 static void network_free(struct network_ctx
* ctx
) {
126 DEBUG(ctx
, "network ctx %p released\n", ctx
);
128 // Free netlink socket
130 nl_socket_free(ctx
->nl_socket
);
135 NETWORK_EXPORT
int network_new(struct network_ctx
** ctx
) {
136 struct network_ctx
* c
= calloc(1, sizeof(*c
));
140 // Initialise basic variables
143 // Initialise logging
144 c
->log_fn
= log_stderr
;
145 c
->log_priority
= LOG_ERR
;
147 const char* env
= secure_getenv("NETWORK_LOG");
149 network_set_log_priority(c
, log_priority(env
));
151 // Initiate netlink connection
152 int r
= init_netlink(c
);
158 INFO(c
, "network ctx %p created\n", c
);
159 DEBUG(c
, "log_priority=%d\n", c
->log_priority
);
165 NETWORK_EXPORT
struct network_ctx
* network_ref(struct network_ctx
* ctx
) {
173 NETWORK_EXPORT
struct network_ctx
* network_unref(struct network_ctx
* ctx
) {
177 if (--ctx
->refcount
> 0)
184 NETWORK_EXPORT
void network_set_log_fn(struct network_ctx
* ctx
,
185 void (*log_fn
)(struct network_ctx
* ctx
, int priority
, const char* file
,
186 int line
, const char* fn
, const char* format
, va_list args
)) {
187 ctx
->log_fn
= log_fn
;
188 INFO(ctx
, "custom logging function %p registered\n", log_fn
);
191 NETWORK_EXPORT
int network_get_log_priority(struct network_ctx
* ctx
) {
192 return ctx
->log_priority
;
195 NETWORK_EXPORT
void network_set_log_priority(struct network_ctx
* ctx
, int priority
) {
196 ctx
->log_priority
= priority
;
199 NETWORK_EXPORT
const char* network_version() {
200 return "network " VERSION
;
203 // Creates a netlink message that can be sent with network_send_netlink_message
204 struct nl_msg
* network_make_netlink_message(struct network_ctx
* ctx
,
205 enum nl80211_commands cmd
, int flags
) {
207 struct nl_msg
* msg
= nlmsg_alloc();
211 genlmsg_put(msg
, 0, 0, ctx
->nl80211_id
, 0, flags
, cmd
, 0);
213 DEBUG(ctx
, "Created new netlink message %p\n", msg
);
218 struct network_netlink_message_status
{
219 struct network_ctx
* ctx
;
223 static int __nl_ack_handler(struct nl_msg
* msg
, void* data
) {
224 struct network_netlink_message_status
* status
= data
;
230 static int __nl_finish_handler(struct nl_msg
* msg
, void* data
) {
231 struct network_netlink_message_status
* status
= data
;
237 static int __nl_error_handler(struct sockaddr_nl
* nla
, struct nlmsgerr
* err
, void* data
) {
238 struct network_netlink_message_status
* status
= data
;
241 struct nlattr
*attrs
;
242 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1];
243 struct nlmsghdr
* nlh
= (struct nlmsghdr
*)err
- 1;
245 size_t len
= nlh
->nlmsg_len
;
246 size_t ack_len
= sizeof(*nlh
) + sizeof(int) + sizeof(*nlh
);
248 status
->r
= err
->error
;
249 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
252 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
253 ack_len
+= err
->msg
.nlmsg_len
- sizeof(*nlh
);
258 attrs
= (void *)((unsigned char *)nlh
+ ack_len
);
261 nla_parse(tb
, NLMSGERR_ATTR_MAX
, attrs
, len
, NULL
);
262 if (tb
[NLMSGERR_ATTR_MSG
]) {
263 len
= strnlen((char *)nla_data(tb
[NLMSGERR_ATTR_MSG
]),
264 nla_len(tb
[NLMSGERR_ATTR_MSG
]));
266 ERROR(status
->ctx
, "Kernel reports: %*s\n", len
,
267 (const char *)nla_data(tb
[NLMSGERR_ATTR_MSG
]));
273 // Sends a netlink message and calls the handler to handle the result
274 int network_send_netlink_message(struct network_ctx
* ctx
, struct nl_msg
* msg
,
275 int(*handler
)(struct nl_msg
* msg
, void* data
), void* data
) {
276 struct network_netlink_message_status status
;
279 DEBUG(ctx
, "Sending netlink message %p\n", msg
);
281 // Sending the message
282 status
.r
= nl_send_auto(ctx
->nl_socket
, msg
);
284 ERROR(ctx
, "Error sending netlink message: %d\n", status
.r
);
289 struct nl_cb
* callback
= nl_cb_alloc(NL_CB_DEFAULT
);
291 ERROR(ctx
, "Could not allocate callback\n");
299 nl_cb_set(callback
, NL_CB_VALID
, NL_CB_CUSTOM
, handler
, data
);
300 nl_cb_set(callback
, NL_CB_ACK
, NL_CB_CUSTOM
, __nl_ack_handler
, &status
);
301 nl_cb_set(callback
, NL_CB_FINISH
, NL_CB_CUSTOM
, __nl_finish_handler
, &status
);
302 nl_cb_err(callback
, NL_CB_CUSTOM
, __nl_error_handler
, &status
);
305 nl_recvmsgs(ctx
->nl_socket
, callback
);
307 DEBUG(ctx
, "Netlink message returned with status %d\n", status
.r
);