update
[ana-net.git] / usr / fbctl.c
blobaec182b3d04414cf445bfd58d46e9ff19fbe9cb7
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 <sys/wait.h>
25 #include <linux/netlink.h>
26 #include <linux/types.h>
27 #include <linux/if.h>
29 #include "xt_user.h"
31 #ifndef likely
32 # define likely(x) __builtin_expect(!!(x), 1)
33 #endif
34 #ifndef unlikely
35 # define unlikely(x) __builtin_expect(!!(x), 0)
36 #endif
37 #ifndef bug
38 # define bug() __builtin_trap()
39 #endif
41 #define PROGNAME "fbctl"
42 #define VERSNAME "0.9"
44 size_t strlcpy(char *dest, const char *src, size_t size)
46 size_t ret = strlen(src);
48 if (size) {
49 size_t len = (ret >= size) ? size - 1 : ret;
50 memcpy(dest, src, len);
51 dest[len] = '\0';
54 return ret;
57 static inline void die(void)
59 exit(EXIT_FAILURE);
62 static inline void panic(char *msg, ...)
64 va_list vl;
65 va_start(vl, msg);
66 vfprintf(stderr, msg, vl);
67 va_end(vl);
69 die();
72 static inline void whine(char *msg, ...)
74 va_list vl;
75 va_start(vl, msg);
76 vfprintf(stderr, msg, vl);
77 va_end(vl);
80 static void *xzmalloc(size_t size)
82 void *ptr;
84 if (unlikely(size == 0))
85 panic("xzmalloc: zero size\n");
87 ptr = malloc(size);
88 if (unlikely(ptr == NULL))
89 panic("xzmalloc: out of memory (allocating %lu bytes)\n",
90 (u_long) size);
91 memset(ptr, 0, size);
93 return ptr;
96 static void xfree(void *ptr)
98 if (unlikely(ptr == NULL))
99 panic("xfree: NULL pointer given as argument\n");
100 free(ptr);
103 void check_for_root_maybe_die(void)
105 if (geteuid() != 0 || geteuid() != getuid())
106 panic("Uhhuh, not root?! \n");
109 static void usage(void)
111 printf("\n%s %s\n", PROGNAME, VERSNAME);
112 printf("Usage: %s <cmd> [<args> ...]\n", PROGNAME);
113 printf("Commands:\n");
114 printf(" preload <module> - preload module\n");
115 printf(" add <name> <type> - add fblock instance\n");
116 printf(" set <name> <key=val> - set option for fblock\n");
117 printf(" rm <name> - remove fblock from stack if unbound\n");
118 printf(" bind <name1> <name2> - bind two fblocks\n");
119 printf(" unbind <name1> <name2> - unbind two fblocks\n");
120 printf(" replace <name1> <name2> - exchange fb1 with fb2 (*)\n");
121 printf(" replace_drop <name1> <name2> - exchange fb1 with fb2 (*)\n");
122 printf(" subscribe <name1> <name2> - subscribe fb2 to fb1 (+)\n");
123 printf(" unsubscribe <name1> <name2> - unsubscribe fb2 from fb1 (+)\n");
124 printf("\n");
125 printf("Note (*):\n");
126 printf(" (*) 'replace' drops functional block <name1> and replaces\n");
127 printf(" it with functional block <name2> where <name1>\n");
128 printf(" now points to the new functional block and <name2>\n");
129 printf(" will be dropped in the namespace.\n");
130 printf(" If both are of the same type, private data will be\n");
131 printf(" transferred to <name2>. If this is unwanted, use\n");
132 printf(" 'replace_drop' instead.\n");
133 printf(" (+) 'subscribe' is used to receive events from other\n");
134 printf(" functional blocks.\n");
135 printf("\n");
136 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
137 printf("Copyright (C) 2011 Daniel Borkmann\n");
138 printf("License: GNU GPL version 2\n");
139 printf("This is free software: you are free to change and redistribute it.\n");
140 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
142 die();
145 static void version(void)
147 printf("\n%s %s\n", PROGNAME, VERSNAME);
148 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
149 printf("Copyright (C) 2011 Daniel Borkmann\n");
150 printf("License: GNU GPL version 2\n");
151 printf("This is free software: you are free to change and redistribute it.\n");
152 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
154 die();
157 static void do_preload(int argc, char **argv)
159 int ret, fd;
160 char path[256], file[320], cmd[512], *env;
161 struct stat sb;
163 if (argc != 1)
164 panic("Invalid args!\n");
166 memset(cmd, 0, sizeof(cmd));
167 env = getenv("FBCFG_PRELOAD_DIR");
168 if (!env) {
169 snprintf(cmd, sizeof(cmd), "modprobe %s", argv[0]);
170 cmd[sizeof(cmd) - 1] = 0;
171 ret = system(cmd);
172 ret = WEXITSTATUS(ret);
173 if (ret != 0)
174 panic("Preload failed!\n");
175 return;
178 memset(path, 0, sizeof(path));
179 memcpy(path, env, sizeof(path));
180 path[sizeof(path) - 1] = 0;
181 memset(file, 0, sizeof(file));
182 snprintf(file, sizeof(file), "%s%s.ko", path, argv[0]);
183 file[sizeof(file) - 1] = 0;
185 fd = open(file, O_RDONLY);
186 if (fd < 0)
187 panic("Module does not exist!\n");
188 ret = fstat(fd, &sb);
189 if (ret < 0)
190 panic("Cannot fstat file!\n");
191 if (!S_ISREG (sb.st_mode))
192 panic("Module is not a regular file!\n");
193 if (sb.st_uid != geteuid())
194 panic("Module is not owned by root! Someone could "
195 "compromise your system!\n");
196 close(fd);
198 snprintf(cmd, sizeof(cmd), "insmod %s", file);
199 cmd[sizeof(cmd) - 1] = 0;
200 ret = system(cmd);
201 ret = WEXITSTATUS(ret);
202 if (ret != 0)
203 panic("Preload failed!\n");
206 static void send_netlink(struct lananlmsg *lmsg)
208 int sock, ret;
209 struct sockaddr_nl src_addr, dest_addr;
210 struct nlmsghdr *nlh;
211 struct iovec iov;
212 struct msghdr msg;
214 if (unlikely(!lmsg))
215 return;
217 sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERCTL);
218 if (unlikely(sock < 0))
219 panic("Cannot get NETLINK_USERCTL socket from kernel! "
220 "Modules not loaded?!\n");
222 memset(&src_addr, 0, sizeof(src_addr));
223 src_addr.nl_family = AF_NETLINK;
224 src_addr.nl_pad = 0;
225 src_addr.nl_pid = getpid();
226 src_addr.nl_groups = 0;
228 ret = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr));
229 if (unlikely(ret))
230 panic("Cannot bind socket!\n");
232 memset(&dest_addr, 0, sizeof(dest_addr));
233 dest_addr.nl_family = AF_NETLINK;
234 dest_addr.nl_pad = 0;
235 dest_addr.nl_pid = 0;
236 dest_addr.nl_groups = 0;
238 nlh = xzmalloc(NLMSG_SPACE(sizeof(*lmsg)));
239 nlh->nlmsg_len = NLMSG_SPACE(sizeof(*lmsg));
240 nlh->nlmsg_pid = getpid();
241 nlh->nlmsg_type = USERCTLGRP_CONF;
242 nlh->nlmsg_flags = NLM_F_REQUEST;
244 memcpy(NLMSG_DATA(nlh), lmsg, sizeof(*lmsg));
246 iov.iov_base = nlh;
247 iov.iov_len = nlh->nlmsg_len;
249 memset(&msg, 0, sizeof(msg));
250 msg.msg_name = &dest_addr;
251 msg.msg_namelen = sizeof(dest_addr);
252 msg.msg_iov = &iov;
253 msg.msg_iovlen = 1;
255 ret = sendmsg(sock, &msg, 0);
256 if (unlikely(ret < 0))
257 panic("Cannot send NETLINK message to the kernel!\n");
259 close(sock);
260 xfree(nlh);
263 static void do_add(int argc, char **argv)
265 struct lananlmsg lmsg;
266 struct lananlmsg_add *msg;
268 if (argc != 2)
269 usage();
271 memset(&lmsg, 0, sizeof(lmsg));
272 lmsg.cmd = NETLINK_USERCTL_CMD_ADD;
273 msg = (struct lananlmsg_add *) lmsg.buff;
274 strlcpy(msg->name, argv[0], sizeof(msg->name));
275 strlcpy(msg->type, argv[1], sizeof(msg->type));
276 send_netlink(&lmsg);
279 static void do_set(int argc, char **argv)
281 struct lananlmsg lmsg;
282 struct lananlmsg_set *msg;
284 if (argc != 2)
285 usage();
287 memset(&lmsg, 0, sizeof(lmsg));
288 lmsg.cmd = NETLINK_USERCTL_CMD_SET;
289 msg = (struct lananlmsg_set *) lmsg.buff;
290 strlcpy(msg->name, argv[0], sizeof(msg->name));
291 strlcpy(msg->option, argv[1], sizeof(msg->option));
292 send_netlink(&lmsg);
295 static void do_rm(int argc, char **argv)
297 struct lananlmsg lmsg;
298 struct lananlmsg_rm *msg;
300 if (argc != 1)
301 usage();
303 memset(&lmsg, 0, sizeof(lmsg));
304 lmsg.cmd = NETLINK_USERCTL_CMD_RM;
305 msg = (struct lananlmsg_rm *) lmsg.buff;
306 strlcpy(msg->name, argv[0], sizeof(msg->name));
307 send_netlink(&lmsg);
310 static void do_bind(int argc, char **argv)
312 struct lananlmsg lmsg;
313 struct lananlmsg_bind *msg;
315 if (argc != 2)
316 usage();
318 memset(&lmsg, 0, sizeof(lmsg));
319 lmsg.cmd = NETLINK_USERCTL_CMD_BIND;
320 msg = (struct lananlmsg_bind *) lmsg.buff;
321 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
322 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
323 send_netlink(&lmsg);
326 static void do_unbind(int argc, char **argv)
328 struct lananlmsg lmsg;
329 struct lananlmsg_unbind *msg;
331 if (argc != 2)
332 usage();
334 memset(&lmsg, 0, sizeof(lmsg));
335 lmsg.cmd = NETLINK_USERCTL_CMD_UNBIND;
336 msg = (struct lananlmsg_unbind *) lmsg.buff;
337 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
338 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
339 send_netlink(&lmsg);
342 static void do_replace(int argc, char **argv, int drop)
344 struct lananlmsg lmsg;
345 struct lananlmsg_replace *msg;
347 if (argc != 2)
348 usage();
350 memset(&lmsg, 0, sizeof(lmsg));
351 lmsg.cmd = NETLINK_USERCTL_CMD_REPLACE;
352 msg = (struct lananlmsg_replace *) lmsg.buff;
353 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
354 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
355 msg->drop_priv = !!drop;
356 send_netlink(&lmsg);
359 static void do_subscribe(int argc, char **argv)
361 struct lananlmsg lmsg;
362 struct lananlmsg_subscribe *msg;
364 if (argc != 2)
365 usage();
367 memset(&lmsg, 0, sizeof(lmsg));
368 lmsg.cmd = NETLINK_USERCTL_CMD_SUBSCRIBE;
369 msg = (struct lananlmsg_subscribe *) lmsg.buff;
370 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
371 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
372 send_netlink(&lmsg);
375 static void do_unsubscribe(int argc, char **argv)
377 struct lananlmsg lmsg;
378 struct lananlmsg_unsubscribe *msg;
380 if (argc != 2)
381 usage();
383 memset(&lmsg, 0, sizeof(lmsg));
384 lmsg.cmd = NETLINK_USERCTL_CMD_UNSUBSCRIBE;
385 msg = (struct lananlmsg_unsubscribe *) lmsg.buff;
386 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
387 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
388 send_netlink(&lmsg);
391 int main(int argc, char **argv)
393 check_for_root_maybe_die();
395 if (argc <= 1)
396 usage();
397 argc--; argv++;
398 if (!strncmp("help", argv[0], strlen("help")))
399 usage();
400 else if (!strncmp("version", argv[0], strlen("version")))
401 version();
402 else if (!strncmp("preload", argv[0], strlen("preload")))
403 do_preload(--argc, ++argv);
404 else if (!strncmp("add", argv[0], strlen("add")))
405 do_add(--argc, ++argv);
406 else if (!strncmp("set", argv[0], strlen("set")))
407 do_set(--argc, ++argv);
408 else if (!strncmp("rm", argv[0], strlen("rm")))
409 do_rm(--argc, ++argv);
410 else if (!strncmp("bind", argv[0], strlen("bind")))
411 do_bind(--argc, ++argv);
412 else if (!strncmp("unbind", argv[0], strlen("unbind")))
413 do_unbind(--argc, ++argv);
414 else if (!strncmp("replace", argv[0], strlen("replace")))
415 do_replace(--argc, ++argv, 0);
416 else if (!strncmp("replace-drop", argv[0], strlen("replace-drop")))
417 do_replace(--argc, ++argv, 1);
418 else if (!strncmp("subscribe", argv[0], strlen("subscribe")))
419 do_subscribe(--argc, ++argv);
420 else if (!strncmp("unsubscribe", argv[0], strlen("unsubscribe")))
421 do_unsubscribe(--argc, ++argv);
422 else
423 usage();
425 return 0;