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)
22 #include <sys/socket.h>
23 #include <sys/types.h>
25 #include <linux/netlink.h>
26 #include <linux/types.h>
32 # define likely(x) __builtin_expect(!!(x), 1)
35 # define unlikely(x) __builtin_expect(!!(x), 0)
38 # define bug() __builtin_trap()
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
);
49 size_t len
= (ret
>= size
) ? size
- 1 : ret
;
50 memcpy(dest
, src
, len
);
57 static inline void die(void)
62 static inline void panic(char *msg
, ...)
66 vfprintf(stderr
, msg
, vl
);
72 static inline void whine(char *msg
, ...)
76 vfprintf(stderr
, msg
, vl
);
80 static void *xzmalloc(size_t size
)
84 if (unlikely(size
== 0))
85 panic("xzmalloc: zero size\n");
88 if (unlikely(ptr
== NULL
))
89 panic("xzmalloc: out of memory (allocating %lu bytes)\n",
96 static void xfree(void *ptr
)
98 if (unlikely(ptr
== NULL
))
99 panic("xfree: NULL pointer given as argument\n");
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");
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");
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");
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");
157 static void do_preload(int argc
, char **argv
)
160 char path
[256], file
[320], cmd
[512], *env
;
164 panic("Invalid args!\n");
166 memset(cmd
, 0, sizeof(cmd
));
167 env
= getenv("FBCFG_PRELOAD_DIR");
169 snprintf(cmd
, sizeof(cmd
), "modprobe %s", argv
[0]);
170 cmd
[sizeof(cmd
) - 1] = 0;
172 ret
= WEXITSTATUS(ret
);
174 panic("Preload failed!\n");
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
);
187 panic("Module does not exist!\n");
188 ret
= fstat(fd
, &sb
);
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");
198 snprintf(cmd
, sizeof(cmd
), "insmod %s", file
);
199 cmd
[sizeof(cmd
) - 1] = 0;
201 ret
= WEXITSTATUS(ret
);
203 panic("Preload failed!\n");
206 static void send_netlink(struct lananlmsg
*lmsg
)
209 struct sockaddr_nl src_addr
, dest_addr
;
210 struct nlmsghdr
*nlh
;
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
;
225 src_addr
.nl_pid
= getpid();
226 src_addr
.nl_groups
= 0;
228 ret
= bind(sock
, (struct sockaddr
*) &src_addr
, sizeof(src_addr
));
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
));
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
);
255 ret
= sendmsg(sock
, &msg
, 0);
256 if (unlikely(ret
< 0))
257 panic("Cannot send NETLINK message to the kernel!\n");
263 static void do_add(int argc
, char **argv
)
265 struct lananlmsg lmsg
;
266 struct lananlmsg_add
*msg
;
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
));
279 static void do_set(int argc
, char **argv
)
281 struct lananlmsg lmsg
;
282 struct lananlmsg_set
*msg
;
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
));
295 static void do_rm(int argc
, char **argv
)
297 struct lananlmsg lmsg
;
298 struct lananlmsg_rm
*msg
;
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
));
310 static void do_bind(int argc
, char **argv
)
312 struct lananlmsg lmsg
;
313 struct lananlmsg_bind
*msg
;
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
));
326 static void do_unbind(int argc
, char **argv
)
328 struct lananlmsg lmsg
;
329 struct lananlmsg_unbind
*msg
;
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
));
342 static void do_replace(int argc
, char **argv
, int drop
)
344 struct lananlmsg lmsg
;
345 struct lananlmsg_replace
*msg
;
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
;
359 static void do_subscribe(int argc
, char **argv
)
361 struct lananlmsg lmsg
;
362 struct lananlmsg_subscribe
*msg
;
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
));
375 static void do_unsubscribe(int argc
, char **argv
)
377 struct lananlmsg lmsg
;
378 struct lananlmsg_unsubscribe
*msg
;
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
));
391 int main(int argc
, char **argv
)
393 check_for_root_maybe_die();
398 if (!strncmp("help", argv
[0], strlen("help")))
400 else if (!strncmp("version", argv
[0], strlen("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
);