implemented cmds in fbctl
[ana-net.git] / usr / fbctl.c
bloba042b43dcb15edbd9af51aa9afba68fc05d9ccf3
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> and\n");
127 printf(" <name2> now point to the same functional block. If\n");
128 printf(" both are of the same type, private data will be\n");
129 printf(" transferred to <name2>. If this is unwanted, use\n");
130 printf(" 'replace_drop' instead.\n");
131 printf(" (+) 'subscribe' is used to receive events from other\n");
132 printf(" functional blocks.\n");
133 printf("\n");
134 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
135 printf("Copyright (C) 2011 Daniel Borkmann\n");
136 printf("License: GNU GPL version 2\n");
137 printf("This is free software: you are free to change and redistribute it.\n");
138 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
140 die();
143 static void version(void)
145 printf("\n%s %s\n", PROGNAME, VERSNAME);
146 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
147 printf("Copyright (C) 2011 Daniel Borkmann\n");
148 printf("License: GNU GPL version 2\n");
149 printf("This is free software: you are free to change and redistribute it.\n");
150 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
152 die();
155 static void do_preload(int argc, char **argv)
157 int ret, fd;
158 char path[256], file[320], cmd[512], *env;
159 struct stat sb;
161 if (argc != 1)
162 panic("Invalid args!\n");
164 memset(cmd, 0, sizeof(cmd));
165 env = getenv("FBCFG_PRELOAD_DIR");
166 if (!env) {
167 snprintf(cmd, sizeof(cmd), "modprobe %s", argv[0]);
168 cmd[sizeof(cmd) - 1] = 0;
169 ret = system(cmd);
170 ret = WEXITSTATUS(ret);
171 if (ret != 0)
172 panic("Preload failed!\n");
173 return;
176 memset(path, 0, sizeof(path));
177 memcpy(path, env, sizeof(path));
178 path[sizeof(path) - 1] = 0;
179 memset(file, 0, sizeof(file));
180 snprintf(file, sizeof(file), "%s%s.ko", path, argv[0]);
181 file[sizeof(file) - 1] = 0;
183 fd = open(file, O_RDONLY);
184 if (fd < 0)
185 panic("Module does not exist!\n");
186 ret = fstat(fd, &sb);
187 if (ret < 0)
188 panic("Cannot fstat file!\n");
189 if (!S_ISREG (sb.st_mode))
190 panic("Module is not a regular file!\n");
191 if (sb.st_uid != geteuid())
192 panic("Module is not owned by root! Someone could "
193 "compromise your system!\n");
194 close(fd);
196 snprintf(cmd, sizeof(cmd), "insmod %s", file);
197 cmd[sizeof(cmd) - 1] = 0;
198 ret = system(cmd);
199 ret = WEXITSTATUS(ret);
200 if (ret != 0)
201 panic("Preload failed!\n");
204 static void send_netlink(struct lananlmsg *lmsg)
206 int sock, ret;
207 struct sockaddr_nl src_addr, dest_addr;
208 struct nlmsghdr *nlh;
209 struct iovec iov;
210 struct msghdr msg;
212 if (unlikely(!lmsg))
213 return;
215 sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERCTL);
216 if (unlikely(sock < 0))
217 panic("Cannot get NETLINK_USERCTL socket from kernel! "
218 "Modules not loaded?!\n");
220 memset(&src_addr, 0, sizeof(src_addr));
221 src_addr.nl_family = AF_NETLINK;
222 src_addr.nl_pad = 0;
223 src_addr.nl_pid = getpid();
224 src_addr.nl_groups = 0;
226 ret = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr));
227 if (unlikely(ret))
228 panic("Cannot bind socket!\n");
230 memset(&dest_addr, 0, sizeof(dest_addr));
231 dest_addr.nl_family = AF_NETLINK;
232 dest_addr.nl_pad = 0;
233 dest_addr.nl_pid = 0;
234 dest_addr.nl_groups = 0;
236 nlh = xzmalloc(NLMSG_SPACE(sizeof(*lmsg)));
237 nlh->nlmsg_len = NLMSG_SPACE(sizeof(*lmsg));
238 nlh->nlmsg_pid = getpid();
239 nlh->nlmsg_type = USERCTLGRP_CONF;
240 nlh->nlmsg_flags = NLM_F_REQUEST;
242 memcpy(NLMSG_DATA(nlh), lmsg, sizeof(*lmsg));
244 iov.iov_base = nlh;
245 iov.iov_len = nlh->nlmsg_len;
247 memset(&msg, 0, sizeof(msg));
248 msg.msg_name = &dest_addr;
249 msg.msg_namelen = sizeof(dest_addr);
250 msg.msg_iov = &iov;
251 msg.msg_iovlen = 1;
253 ret = sendmsg(sock, &msg, 0);
254 if (unlikely(ret < 0))
255 panic("Cannot send NETLINK message to the kernel!\n");
257 close(sock);
258 xfree(nlh);
261 static void do_add(int argc, char **argv)
263 struct lananlmsg lmsg;
264 struct lananlmsg_add *msg;
266 if (argc != 2)
267 usage();
269 memset(&lmsg, 0, sizeof(lmsg));
270 lmsg.cmd = NETLINK_USERCTL_CMD_ADD;
271 msg = (struct lananlmsg_add *) lmsg.buff;
272 strlcpy(msg->name, argv[0], sizeof(msg->name));
273 strlcpy(msg->type, argv[1], sizeof(msg->type));
274 send_netlink(&lmsg);
277 static void do_set(int argc, char **argv)
279 struct lananlmsg lmsg;
280 struct lananlmsg_set *msg;
282 if (argc != 2)
283 usage();
285 memset(&lmsg, 0, sizeof(lmsg));
286 lmsg.cmd = NETLINK_USERCTL_CMD_SET;
287 msg = (struct lananlmsg_set *) lmsg.buff;
288 strlcpy(msg->name, argv[0], sizeof(msg->name));
289 strlcpy(msg->option, argv[1], sizeof(msg->option));
290 send_netlink(&lmsg);
293 static void do_rm(int argc, char **argv)
295 struct lananlmsg lmsg;
296 struct lananlmsg_rm *msg;
298 if (argc != 1)
299 usage();
301 memset(&lmsg, 0, sizeof(lmsg));
302 lmsg.cmd = NETLINK_USERCTL_CMD_RM;
303 msg = (struct lananlmsg_rm *) lmsg.buff;
304 strlcpy(msg->name, argv[0], sizeof(msg->name));
305 send_netlink(&lmsg);
308 static void do_bind(int argc, char **argv)
310 struct lananlmsg lmsg;
311 struct lananlmsg_bind *msg;
313 if (argc != 2)
314 usage();
316 memset(&lmsg, 0, sizeof(lmsg));
317 lmsg.cmd = NETLINK_USERCTL_CMD_BIND;
318 msg = (struct lananlmsg_bind *) lmsg.buff;
319 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
320 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
321 send_netlink(&lmsg);
324 static void do_unbind(int argc, char **argv)
326 struct lananlmsg lmsg;
327 struct lananlmsg_unbind *msg;
329 if (argc != 2)
330 usage();
332 memset(&lmsg, 0, sizeof(lmsg));
333 lmsg.cmd = NETLINK_USERCTL_CMD_UNBIND;
334 msg = (struct lananlmsg_unbind *) lmsg.buff;
335 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
336 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
337 send_netlink(&lmsg);
340 static void do_replace(int argc, char **argv, int drop)
342 struct lananlmsg lmsg;
343 struct lananlmsg_replace *msg;
345 if (argc != 2)
346 usage();
348 memset(&lmsg, 0, sizeof(lmsg));
349 lmsg.cmd = NETLINK_USERCTL_CMD_REPLACE;
350 msg = (struct lananlmsg_replace *) lmsg.buff;
351 msg->drop_priv = drop;
352 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
353 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
354 send_netlink(&lmsg);
357 static void do_subscribe(int argc, char **argv)
359 struct lananlmsg lmsg;
360 struct lananlmsg_subscribe *msg;
362 if (argc != 2)
363 usage();
365 memset(&lmsg, 0, sizeof(lmsg));
366 lmsg.cmd = NETLINK_USERCTL_CMD_SUBSCRIBE;
367 msg = (struct lananlmsg_subscribe *) lmsg.buff;
368 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
369 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
370 send_netlink(&lmsg);
373 static void do_unsubscribe(int argc, char **argv)
375 struct lananlmsg lmsg;
376 struct lananlmsg_unsubscribe *msg;
378 if (argc != 2)
379 usage();
381 memset(&lmsg, 0, sizeof(lmsg));
382 lmsg.cmd = NETLINK_USERCTL_CMD_UNSUBSCRIBE;
383 msg = (struct lananlmsg_unsubscribe *) lmsg.buff;
384 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
385 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
386 send_netlink(&lmsg);
389 int main(int argc, char **argv)
391 check_for_root_maybe_die();
393 if (argc <= 1)
394 usage();
395 argc--; argv++;
396 if (!strncmp("help", argv[0], strlen("help")))
397 usage();
398 else if (!strncmp("version", argv[0], strlen("version")))
399 version();
400 else if (!strncmp("preload", argv[0], strlen("preload")))
401 do_preload(--argc, ++argv);
402 else if (!strncmp("add", argv[0], strlen("add")))
403 do_add(--argc, ++argv);
404 else if (!strncmp("set", argv[0], strlen("set")))
405 do_set(--argc, ++argv);
406 else if (!strncmp("rm", argv[0], strlen("rm")))
407 do_rm(--argc, ++argv);
408 else if (!strncmp("bind", argv[0], strlen("bind")))
409 do_bind(--argc, ++argv);
410 else if (!strncmp("unbind", argv[0], strlen("unbind")))
411 do_unbind(--argc, ++argv);
412 else if (!strncmp("replace", argv[0], strlen("replace")))
413 do_replace(--argc, ++argv, 0);
414 else if (!strncmp("replace-drop", argv[0], strlen("replace-drop")))
415 do_replace(--argc, ++argv, 1);
416 else if (!strncmp("subscribe", argv[0], strlen("subscribe")))
417 do_subscribe(--argc, ++argv);
418 else if (!strncmp("unsubscribe", argv[0], strlen("unsubscribe")))
419 do_unsubscribe(--argc, ++argv);
420 else
421 usage();
423 return 0;