fixed description in fbctl
[ana-net.git] / usr / fbctl.c
blob198cdf4d373fe1d215832192283b20b972547be0
1 /*
2 * Lightweight Autonomic Network Architecture
4 * Functional block userspace configuration tool for LANA.
6 * strlcpy taken from the Linux kernel.
7 * Copyright 1991, 1992 Linus Torvalds <torvalds@linux-foundation.org>
9 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
10 * Swiss federal institute of technology (ETH Zurich)
11 * Subject to the GPL.
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <stdarg.h>
20 #include <fcntl.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <linux/netlink.h>
25 #include <linux/types.h>
26 #include <linux/if.h>
28 #include "xt_user.h"
30 #ifndef likely
31 # define likely(x) __builtin_expect(!!(x), 1)
32 #endif
33 #ifndef unlikely
34 # define unlikely(x) __builtin_expect(!!(x), 0)
35 #endif
36 #ifndef bug
37 # define bug() __builtin_trap()
38 #endif
40 #define PROGNAME "fbctl"
41 #define VERSNAME "0.9"
43 size_t strlcpy(char *dest, const char *src, size_t size)
45 size_t ret = strlen(src);
47 if (size) {
48 size_t len = (ret >= size) ? size - 1 : ret;
49 memcpy(dest, src, len);
50 dest[len] = '\0';
53 return ret;
56 static inline void die(void)
58 exit(EXIT_FAILURE);
61 static inline void panic(char *msg, ...)
63 va_list vl;
64 va_start(vl, msg);
65 vfprintf(stderr, msg, vl);
66 va_end(vl);
68 die();
71 static inline void whine(char *msg, ...)
73 va_list vl;
74 va_start(vl, msg);
75 vfprintf(stderr, msg, vl);
76 va_end(vl);
79 static void *xzmalloc(size_t size)
81 void *ptr;
83 if (unlikely(size == 0))
84 panic("xzmalloc: zero size\n");
86 ptr = malloc(size);
87 if (unlikely(ptr == NULL))
88 panic("xzmalloc: out of memory (allocating %lu bytes)\n",
89 (u_long) size);
90 memset(ptr, 0, size);
92 return ptr;
95 static void xfree(void *ptr)
97 if (unlikely(ptr == NULL))
98 panic("xfree: NULL pointer given as argument\n");
99 free(ptr);
102 void check_for_root_maybe_die(void)
104 if (geteuid() != 0 || geteuid() != getuid())
105 panic("Uhhuh, not root?! \n");
108 static void usage(void)
110 printf("\n%s %s\n", PROGNAME, VERSNAME);
111 printf("Usage: %s <cmd> [<args> ...]\n", PROGNAME);
112 printf("Commands:\n");
113 printf(" preload <module> - preload module\n");
114 printf(" add <name> <type> - add fblock instance\n");
115 printf(" set <name> <key=val> - set option for fblock\n");
116 printf(" rm <name> - remove fblock from stack if unbound\n");
117 printf(" bind <name1> <name2> - bind two fblocks\n");
118 printf(" unbind <name1> <name2> - unbind two fblocks\n");
119 printf(" replace <name1> <name2> - exchange fb1 with fb2 (*)\n");
120 printf(" replace_drop <name1> <name2> - exchange fb1 with fb2 (*)\n");
121 printf(" subscribe <name1> <name2> - subscribe fb2 to fb1 (+)\n");
122 printf(" unsubscribe <name1> <name2> - unsubscribe fb2 from fb1 (+)\n");
123 printf("\n");
124 printf("Note (*):\n");
125 printf(" (*) 'replace' drops functional block <name1> and replaces\n");
126 printf(" it with functional block <name2> where <name1>\n");
127 printf(" now points to the new functional block and <name2>\n");
128 printf(" will be dropped in the namespace.\n");
129 printf(" If both are of the same type, private data will be\n");
130 printf(" transferred to <name2>. If this is unwanted, use\n");
131 printf(" 'replace_drop' instead.\n");
132 printf(" (+) 'subscribe' is used to receive events from other\n");
133 printf(" functional blocks.\n");
134 printf("\n");
135 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
136 printf("Copyright (C) 2011 Daniel Borkmann\n");
137 printf("License: GNU GPL version 2\n");
138 printf("This is free software: you are free to change and redistribute it.\n");
139 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
141 die();
144 static void version(void)
146 printf("\n%s %s\n", PROGNAME, VERSNAME);
147 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
148 printf("Copyright (C) 2011 Daniel Borkmann\n");
149 printf("License: GNU GPL version 2\n");
150 printf("This is free software: you are free to change and redistribute it.\n");
151 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
153 die();
156 static void do_preload(int argc, char **argv)
158 int ret, fd;
159 char path[256], file[320], cmd[512], *env;
160 struct stat sb;
162 if (argc != 1)
163 panic("Invalid args!\n");
165 memset(cmd, 0, sizeof(cmd));
166 env = getenv("FBCFG_PRELOAD_DIR");
167 if (!env) {
168 snprintf(cmd, sizeof(cmd), "modprobe %s", argv[0]);
169 cmd[sizeof(cmd) - 1] = 0;
170 ret = system(cmd);
171 ret = WEXITSTATUS(ret);
172 if (ret != 0)
173 panic("Preload failed!\n");
174 return;
177 memset(path, 0, sizeof(path));
178 memcpy(path, env, sizeof(path));
179 path[sizeof(path) - 1] = 0;
180 memset(file, 0, sizeof(file));
181 snprintf(file, sizeof(file), "%s%s.ko", path, argv[0]);
182 file[sizeof(file) - 1] = 0;
184 fd = open(file, O_RDONLY);
185 if (fd < 0)
186 panic("Module does not exist!\n");
187 ret = fstat(fd, &sb);
188 if (ret < 0)
189 panic("Cannot fstat file!\n");
190 if (!S_ISREG (sb.st_mode))
191 panic("Module is not a regular file!\n");
192 if (sb.st_uid != geteuid())
193 panic("Module is not owned by root! Someone could "
194 "compromise your system!\n");
195 close(fd);
197 snprintf(cmd, sizeof(cmd), "insmod %s", file);
198 cmd[sizeof(cmd) - 1] = 0;
199 ret = system(cmd);
200 ret = WEXITSTATUS(ret);
201 if (ret != 0)
202 panic("Preload failed!\n");
205 static void send_netlink(struct lananlmsg *lmsg)
207 int sock, ret;
208 struct sockaddr_nl src_addr, dest_addr;
209 struct nlmsghdr *nlh;
210 struct iovec iov;
211 struct msghdr msg;
213 if (unlikely(!lmsg))
214 return;
216 sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERCTL);
217 if (unlikely(sock < 0))
218 panic("Cannot get NETLINK_USERCTL socket from kernel! "
219 "Modules not loaded?!\n");
221 memset(&src_addr, 0, sizeof(src_addr));
222 src_addr.nl_family = AF_NETLINK;
223 src_addr.nl_pad = 0;
224 src_addr.nl_pid = getpid();
225 src_addr.nl_groups = 0;
227 ret = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr));
228 if (unlikely(ret))
229 panic("Cannot bind socket!\n");
231 memset(&dest_addr, 0, sizeof(dest_addr));
232 dest_addr.nl_family = AF_NETLINK;
233 dest_addr.nl_pad = 0;
234 dest_addr.nl_pid = 0;
235 dest_addr.nl_groups = 0;
237 nlh = xzmalloc(NLMSG_SPACE(sizeof(*lmsg)));
238 nlh->nlmsg_len = NLMSG_SPACE(sizeof(*lmsg));
239 nlh->nlmsg_pid = getpid();
240 nlh->nlmsg_type = USERCTLGRP_CONF;
241 nlh->nlmsg_flags = NLM_F_REQUEST;
243 memcpy(NLMSG_DATA(nlh), lmsg, sizeof(*lmsg));
245 iov.iov_base = nlh;
246 iov.iov_len = nlh->nlmsg_len;
248 memset(&msg, 0, sizeof(msg));
249 msg.msg_name = &dest_addr;
250 msg.msg_namelen = sizeof(dest_addr);
251 msg.msg_iov = &iov;
252 msg.msg_iovlen = 1;
254 ret = sendmsg(sock, &msg, 0);
255 if (unlikely(ret < 0))
256 panic("Cannot send NETLINK message to the kernel!\n");
258 close(sock);
259 xfree(nlh);
262 static void do_add(int argc, char **argv)
264 struct lananlmsg lmsg;
265 struct lananlmsg_add *msg;
267 if (argc != 2)
268 usage();
270 memset(&lmsg, 0, sizeof(lmsg));
271 lmsg.cmd = NETLINK_USERCTL_CMD_ADD;
272 msg = (struct lananlmsg_add *) lmsg.buff;
273 strlcpy(msg->name, argv[0], sizeof(msg->name));
274 strlcpy(msg->type, argv[1], sizeof(msg->type));
275 send_netlink(&lmsg);
278 static void do_set(int argc, char **argv)
280 struct lananlmsg lmsg;
281 struct lananlmsg_set *msg;
283 if (argc != 2)
284 usage();
286 memset(&lmsg, 0, sizeof(lmsg));
287 lmsg.cmd = NETLINK_USERCTL_CMD_SET;
288 msg = (struct lananlmsg_set *) lmsg.buff;
289 strlcpy(msg->name, argv[0], sizeof(msg->name));
290 strlcpy(msg->option, argv[1], sizeof(msg->option));
291 send_netlink(&lmsg);
294 static void do_rm(int argc, char **argv)
296 struct lananlmsg lmsg;
297 struct lananlmsg_rm *msg;
299 if (argc != 1)
300 usage();
302 memset(&lmsg, 0, sizeof(lmsg));
303 lmsg.cmd = NETLINK_USERCTL_CMD_RM;
304 msg = (struct lananlmsg_rm *) lmsg.buff;
305 strlcpy(msg->name, argv[0], sizeof(msg->name));
306 send_netlink(&lmsg);
309 static void do_bind(int argc, char **argv)
311 struct lananlmsg lmsg;
312 struct lananlmsg_bind *msg;
314 if (argc != 2)
315 usage();
317 memset(&lmsg, 0, sizeof(lmsg));
318 lmsg.cmd = NETLINK_USERCTL_CMD_BIND;
319 msg = (struct lananlmsg_bind *) lmsg.buff;
320 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
321 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
322 send_netlink(&lmsg);
325 static void do_unbind(int argc, char **argv)
327 struct lananlmsg lmsg;
328 struct lananlmsg_unbind *msg;
330 if (argc != 2)
331 usage();
333 memset(&lmsg, 0, sizeof(lmsg));
334 lmsg.cmd = NETLINK_USERCTL_CMD_UNBIND;
335 msg = (struct lananlmsg_unbind *) lmsg.buff;
336 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
337 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
338 send_netlink(&lmsg);
341 static void do_replace(int argc, char **argv, int drop)
343 struct lananlmsg lmsg;
344 struct lananlmsg_replace *msg;
346 if (argc != 2)
347 usage();
349 memset(&lmsg, 0, sizeof(lmsg));
350 lmsg.cmd = NETLINK_USERCTL_CMD_REPLACE;
351 msg = (struct lananlmsg_replace *) lmsg.buff;
352 msg->drop_priv = drop;
353 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
354 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
355 send_netlink(&lmsg);
358 static void do_subscribe(int argc, char **argv)
360 struct lananlmsg lmsg;
361 struct lananlmsg_subscribe *msg;
363 if (argc != 2)
364 usage();
366 memset(&lmsg, 0, sizeof(lmsg));
367 lmsg.cmd = NETLINK_USERCTL_CMD_SUBSCRIBE;
368 msg = (struct lananlmsg_subscribe *) lmsg.buff;
369 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
370 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
371 send_netlink(&lmsg);
374 static void do_unsubscribe(int argc, char **argv)
376 struct lananlmsg lmsg;
377 struct lananlmsg_unsubscribe *msg;
379 if (argc != 2)
380 usage();
382 memset(&lmsg, 0, sizeof(lmsg));
383 lmsg.cmd = NETLINK_USERCTL_CMD_UNSUBSCRIBE;
384 msg = (struct lananlmsg_unsubscribe *) lmsg.buff;
385 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
386 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
387 send_netlink(&lmsg);
390 int main(int argc, char **argv)
392 check_for_root_maybe_die();
394 if (argc <= 1)
395 usage();
396 argc--; argv++;
397 if (!strncmp("help", argv[0], strlen("help")))
398 usage();
399 else if (!strncmp("version", argv[0], strlen("version")))
400 version();
401 else if (!strncmp("preload", argv[0], strlen("preload")))
402 do_preload(--argc, ++argv);
403 else if (!strncmp("add", argv[0], strlen("add")))
404 do_add(--argc, ++argv);
405 else if (!strncmp("set", argv[0], strlen("set")))
406 do_set(--argc, ++argv);
407 else if (!strncmp("rm", argv[0], strlen("rm")))
408 do_rm(--argc, ++argv);
409 else if (!strncmp("bind", argv[0], strlen("bind")))
410 do_bind(--argc, ++argv);
411 else if (!strncmp("unbind", argv[0], strlen("unbind")))
412 do_unbind(--argc, ++argv);
413 else if (!strncmp("replace", argv[0], strlen("replace")))
414 do_replace(--argc, ++argv, 0);
415 else if (!strncmp("replace-drop", argv[0], strlen("replace-drop")))
416 do_replace(--argc, ++argv, 1);
417 else if (!strncmp("subscribe", argv[0], strlen("subscribe")))
418 do_subscribe(--argc, ++argv);
419 else if (!strncmp("unsubscribe", argv[0], strlen("unsubscribe")))
420 do_unsubscribe(--argc, ++argv);
421 else
422 usage();
424 return 0;