changed name
[ana-net.git] / usr / fbctl.c
blob6961c1fe00e6faf082092dcf3a2f23234a5d25c8
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)
105 panic("Uhhuh, not root?! \n");
106 if (geteuid() != getuid())
107 panic("Uhhuh, not root?! \n");
110 static void usage(void)
112 printf("\n%s %s\n", PROGNAME, VERSNAME);
113 printf("Usage: %s <cmd> [<args> ...]\n", PROGNAME);
114 printf("Commands:\n");
115 printf(" preload <module> - preload module\n");
116 printf(" add <name> <type> - add fblock instance\n");
117 printf(" set <name> <key=val> - set option for fblock\n");
118 printf(" rm <name> - remove fblock from stack if unbound\n");
119 printf(" bind <name1> <name2> - bind two fblocks\n");
120 printf(" unbind <name1> <name2> - unbind two fblocks\n");
121 printf(" xchg <name1> <name2> - exchange fb1 with fb2\n");
122 printf(" note: name1 and name2 then \n");
123 printf(" point to the same fblock\n");
124 printf(" subscribe <name1> <name2> - subscribe fb2 to fb1 to rcv events\n");
125 printf(" unsubscribe <name1> <name2> - unsubscribe fb2 from fb1\n");
126 printf("\n");
127 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
128 printf("Copyright (C) 2011 Daniel Borkmann\n");
129 printf("License: GNU GPL version 2\n");
130 printf("This is free software: you are free to change and redistribute it.\n");
131 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
133 die();
136 static void version(void)
138 printf("\n%s %s\n", PROGNAME, VERSNAME);
139 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
140 printf("Copyright (C) 2011 Daniel Borkmann\n");
141 printf("License: GNU GPL version 2\n");
142 printf("This is free software: you are free to change and redistribute it.\n");
143 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
145 die();
148 static void do_preload(int argc, char **argv)
150 int ret, fd;
151 char path[256], file[320], cmd[512], *env;
152 struct stat sb;
154 if (argc != 1)
155 panic("Invalid args!\n");
157 memset(cmd, 0, sizeof(cmd));
158 env = getenv("FBCFG_PRELOAD_DIR");
159 if (!env) {
160 snprintf(cmd, sizeof(cmd), "modprobe %s", argv[0]);
161 cmd[sizeof(cmd) - 1] = 0;
162 ret = system(cmd);
163 ret = WEXITSTATUS(ret);
164 if (ret != 0)
165 panic("Preload failed!\n");
166 return;
169 memset(path, 0, sizeof(path));
170 memcpy(path, env, sizeof(path));
171 path[sizeof(path) - 1] = 0;
172 memset(file, 0, sizeof(file));
173 snprintf(file, sizeof(file), "%s%s.ko", path, argv[0]);
174 file[sizeof(file) - 1] = 0;
176 fd = open(file, O_RDONLY);
177 if (fd < 0)
178 panic("Module does not exist!\n");
179 ret = fstat(fd, &sb);
180 if (ret < 0)
181 panic("Cannot fstat file!\n");
182 if (!S_ISREG (sb.st_mode))
183 panic("Module is not a regular file!\n");
184 if (sb.st_uid != geteuid())
185 panic("Module is not owned by root! Someone could "
186 "compromise your system!\n");
187 close(fd);
189 snprintf(cmd, sizeof(cmd), "insmod %s", file);
190 cmd[sizeof(cmd) - 1] = 0;
191 ret = system(cmd);
192 ret = WEXITSTATUS(ret);
193 if (ret != 0)
194 panic("Preload failed!\n");
197 static void send_netlink(struct lananlmsg *lmsg)
199 int sock, ret;
200 struct sockaddr_nl src_addr, dest_addr;
201 struct nlmsghdr *nlh;
202 struct iovec iov;
203 struct msghdr msg;
205 if (unlikely(!lmsg))
206 return;
208 sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERCTL);
209 if (unlikely(sock < 0))
210 panic("Cannot get NETLINK_USERCTL socket from kernel! "
211 "Modules not loaded?!\n");
213 memset(&src_addr, 0, sizeof(src_addr));
214 src_addr.nl_family = AF_NETLINK;
215 src_addr.nl_pad = 0;
216 src_addr.nl_pid = getpid();
217 src_addr.nl_groups = 0;
219 ret = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr));
220 if (unlikely(ret))
221 panic("Cannot bind socket!\n");
223 memset(&dest_addr, 0, sizeof(dest_addr));
224 dest_addr.nl_family = AF_NETLINK;
225 dest_addr.nl_pad = 0;
226 dest_addr.nl_pid = 0;
227 dest_addr.nl_groups = 0;
229 nlh = xzmalloc(NLMSG_SPACE(sizeof(*lmsg)));
230 nlh->nlmsg_len = NLMSG_SPACE(sizeof(*lmsg));
231 nlh->nlmsg_pid = getpid();
232 nlh->nlmsg_type = USERCTLGRP_CONF;
233 nlh->nlmsg_flags = NLM_F_REQUEST;
235 memcpy(NLMSG_DATA(nlh), lmsg, sizeof(*lmsg));
237 iov.iov_base = nlh;
238 iov.iov_len = nlh->nlmsg_len;
240 memset(&msg, 0, sizeof(msg));
241 msg.msg_name = &dest_addr;
242 msg.msg_namelen = sizeof(dest_addr);
243 msg.msg_iov = &iov;
244 msg.msg_iovlen = 1;
246 ret = sendmsg(sock, &msg, 0);
247 if (unlikely(ret < 0))
248 panic("Cannot send NETLINK message to the kernel!\n");
250 close(sock);
251 xfree(nlh);
254 static void do_add(int argc, char **argv)
256 struct lananlmsg lmsg;
257 struct lananlmsg_add *msg;
259 if (argc != 2)
260 usage();
262 memset(&lmsg, 0, sizeof(lmsg));
263 lmsg.cmd = NETLINK_USERCTL_CMD_ADD;
264 msg = (struct lananlmsg_add *) lmsg.buff;
265 strlcpy(msg->name, argv[0], sizeof(msg->name));
266 strlcpy(msg->type, argv[1], sizeof(msg->type));
267 send_netlink(&lmsg);
270 static void do_set(int argc, char **argv)
272 struct lananlmsg lmsg;
273 struct lananlmsg_set *msg;
275 if (argc != 2)
276 usage();
278 memset(&lmsg, 0, sizeof(lmsg));
279 lmsg.cmd = NETLINK_USERCTL_CMD_SET;
280 msg = (struct lananlmsg_set *) lmsg.buff;
281 strlcpy(msg->name, argv[0], sizeof(msg->name));
282 strlcpy(msg->option, argv[1], sizeof(msg->option));
283 send_netlink(&lmsg);
286 static void do_rm(int argc, char **argv)
288 struct lananlmsg lmsg;
289 struct lananlmsg_rm *msg;
291 if (argc != 1)
292 usage();
294 memset(&lmsg, 0, sizeof(lmsg));
295 lmsg.cmd = NETLINK_USERCTL_CMD_RM;
296 msg = (struct lananlmsg_rm *) lmsg.buff;
297 strlcpy(msg->name, argv[0], sizeof(msg->name));
298 send_netlink(&lmsg);
301 static void do_bind(int argc, char **argv)
303 struct lananlmsg lmsg;
304 struct lananlmsg_bind *msg;
306 if (argc != 2)
307 usage();
309 memset(&lmsg, 0, sizeof(lmsg));
310 lmsg.cmd = NETLINK_USERCTL_CMD_BIND;
311 msg = (struct lananlmsg_bind *) lmsg.buff;
312 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
313 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
314 send_netlink(&lmsg);
317 static void do_unbind(int argc, char **argv)
319 struct lananlmsg lmsg;
320 struct lananlmsg_unbind *msg;
322 if (argc != 2)
323 usage();
325 memset(&lmsg, 0, sizeof(lmsg));
326 lmsg.cmd = NETLINK_USERCTL_CMD_UNBIND;
327 msg = (struct lananlmsg_unbind *) lmsg.buff;
328 strlcpy(msg->name1, argv[0], sizeof(msg->name1));
329 strlcpy(msg->name2, argv[1], sizeof(msg->name2));
330 send_netlink(&lmsg);
333 int main(int argc, char **argv)
335 check_for_root_maybe_die();
337 if (argc <= 1)
338 usage();
339 argc--; argv++;
340 if (!strncmp("help", argv[0], strlen("help")))
341 usage();
342 else if (!strncmp("version", argv[0], strlen("version")))
343 version();
344 else if (!strncmp("preload", argv[0], strlen("preload")))
345 do_preload(--argc, ++argv);
346 else if (!strncmp("add", argv[0], strlen("add")))
347 do_add(--argc, ++argv);
348 else if (!strncmp("set", argv[0], strlen("set")))
349 do_set(--argc, ++argv);
350 else if (!strncmp("rm", argv[0], strlen("rm")))
351 do_rm(--argc, ++argv);
352 else if (!strncmp("bind", argv[0], strlen("bind")))
353 do_bind(--argc, ++argv);
354 else if (!strncmp("unbind", argv[0], strlen("unbind")))
355 do_unbind(--argc, ++argv);
356 else
357 usage();
359 return 0;