]> git.ipfire.org Git - network.git/blob - src/libnetwork/libnetwork.c
libnetwork: Initialise netlink connection when initialising context
[network.git] / src / libnetwork / libnetwork.c
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2017 IPFire Network Development Team #
5 # #
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. #
10 # #
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. #
15 # #
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/>. #
18 # #
19 #############################################################################*/
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <netlink/genl/ctrl.h>
24 #include <netlink/genl/genl.h>
25 #include <netlink/netlink.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <syslog.h>
31
32 #include <network/libnetwork.h>
33 #include <network/logging.h>
34 #include "libnetwork-private.h"
35
36 struct network_ctx {
37 int refcount;
38
39 // Logging
40 void (*log_fn)(struct network_ctx* ctx,
41 int priority, const char *file, int line, const char *fn,
42 const char *format, va_list args);
43 int log_priority;
44
45 // Netlink
46 struct nl_sock* nl_socket;
47 int nl80211_id;
48 };
49
50 void network_log(struct network_ctx* ctx,
51 int priority, const char* file, int line, const char* fn,
52 const char* format, ...) {
53 va_list args;
54
55 va_start(args, format);
56 ctx->log_fn(ctx, priority, file, line, fn, format, args);
57 va_end(args);
58 }
59
60 static void log_stderr(struct network_ctx* ctx,
61 int priority, const char* file, int line, const char* fn,
62 const char* format, va_list args) {
63 fprintf(stderr, "libnetwork: %s: ", fn);
64 vfprintf(stderr, format, args);
65 }
66
67 static int log_priority(const char* priority) {
68 char *endptr;
69
70 int prio = strtol(priority, &endptr, 10);
71
72 if (endptr[0] == '\0' || isspace(endptr[0]))
73 return prio;
74
75 if (strncmp(priority, "err", 3) == 0)
76 return LOG_ERR;
77
78 if (strncmp(priority, "info", 4) == 0)
79 return LOG_INFO;
80
81 if (strncmp(priority, "debug", 5) == 0)
82 return LOG_DEBUG;
83
84 return 0;
85 }
86
87 static int init_netlink(struct network_ctx* ctx) {
88 // Allocate netlink socket
89 ctx->nl_socket = nl_socket_alloc();
90 if (!ctx->nl_socket) {
91 ERROR(ctx, "Failed to allocate netlink socket\n");
92 return -ENOMEM;
93 }
94
95 // Connect the socket
96 if (genl_connect(ctx->nl_socket)) {
97 ERROR(ctx, "Failed to connect to generic netlink");
98 return -ENOLINK;
99 }
100
101 // Set buffer size
102 nl_socket_set_buffer_size(ctx->nl_socket, 8192, 8192);
103
104 // Get nl80211 id
105 ctx->nl80211_id = genl_ctrl_resolve(ctx->nl_socket, "nl80211");
106 if (ctx->nl80211_id < 0) {
107 ERROR(ctx, "Could not find nl80211\n");
108 return -ENOENT;
109 }
110
111 return 0;
112 }
113
114 static void network_free(struct network_ctx* ctx) {
115 DEBUG(ctx, "network ctx %p released\n", ctx);
116
117 // Free netlink socket
118 if (ctx->nl_socket)
119 nl_socket_free(ctx->nl_socket);
120
121 free(ctx);
122 }
123
124 NETWORK_EXPORT int network_new(struct network_ctx** ctx) {
125 struct network_ctx* c = calloc(1, sizeof(*c));
126 if (!c)
127 return -ENOMEM;
128
129 // Initialise basic variables
130 c->refcount = 1;
131
132 // Initialise logging
133 c->log_fn = log_stderr;
134 c->log_priority = LOG_ERR;
135
136 const char* env = secure_getenv("NETWORK_LOG");
137 if (env)
138 network_set_log_priority(c, log_priority(env));
139
140 // Initiate netlink connection
141 int r = init_netlink(c);
142 if (r) {
143 network_free(c);
144 return r;
145 }
146
147 INFO(c, "network ctx %p created\n", c);
148 DEBUG(c, "log_priority=%d\n", c->log_priority);
149
150 *ctx = c;
151 return 0;
152 }
153
154 NETWORK_EXPORT struct network_ctx* network_ref(struct network_ctx* ctx) {
155 if (!ctx)
156 return NULL;
157
158 ctx->refcount++;
159 return ctx;
160 }
161
162 NETWORK_EXPORT struct network_ctx* network_unref(struct network_ctx* ctx) {
163 if (!ctx)
164 return NULL;
165
166 if (--ctx->refcount > 0)
167 return ctx;
168
169 network_free(ctx);
170 return NULL;
171 }
172
173 NETWORK_EXPORT void network_set_log_fn(struct network_ctx* ctx,
174 void (*log_fn)(struct network_ctx* ctx, int priority, const char* file,
175 int line, const char* fn, const char* format, va_list args)) {
176 ctx->log_fn = log_fn;
177 INFO(ctx, "custom logging function %p registered\n", log_fn);
178 }
179
180 NETWORK_EXPORT int network_get_log_priority(struct network_ctx* ctx) {
181 return ctx->log_priority;
182 }
183
184 NETWORK_EXPORT void network_set_log_priority(struct network_ctx* ctx, int priority) {
185 ctx->log_priority = priority;
186 }
187
188 NETWORK_EXPORT const char* network_version() {
189 return "network " VERSION;
190 }