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>
24 #include <linux/netlink.h>
25 #include <linux/types.h>
31 # define likely(x) __builtin_expect(!!(x), 1)
34 # define unlikely(x) __builtin_expect(!!(x), 0)
37 # define bug() __builtin_trap()
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
);
48 size_t len
= (ret
>= size
) ? size
- 1 : ret
;
49 memcpy(dest
, src
, len
);
56 static inline void die(void)
61 static inline void panic(char *msg
, ...)
65 vfprintf(stderr
, msg
, vl
);
71 static inline void whine(char *msg
, ...)
75 vfprintf(stderr
, msg
, vl
);
79 static void *xzmalloc(size_t size
)
83 if (unlikely(size
== 0))
84 panic("xzmalloc: zero size\n");
87 if (unlikely(ptr
== NULL
))
88 panic("xzmalloc: out of memory (allocating %lu bytes)\n",
95 static void xfree(void *ptr
)
97 if (unlikely(ptr
== NULL
))
98 panic("xfree: NULL pointer given as argument\n");
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");
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");
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");
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");
156 static void do_preload(int argc
, char **argv
)
159 char path
[256], file
[320], cmd
[512], *env
;
163 panic("Invalid args!\n");
165 memset(cmd
, 0, sizeof(cmd
));
166 env
= getenv("FBCFG_PRELOAD_DIR");
168 snprintf(cmd
, sizeof(cmd
), "modprobe %s", argv
[0]);
169 cmd
[sizeof(cmd
) - 1] = 0;
171 ret
= WEXITSTATUS(ret
);
173 panic("Preload failed!\n");
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
);
186 panic("Module does not exist!\n");
187 ret
= fstat(fd
, &sb
);
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");
197 snprintf(cmd
, sizeof(cmd
), "insmod %s", file
);
198 cmd
[sizeof(cmd
) - 1] = 0;
200 ret
= WEXITSTATUS(ret
);
202 panic("Preload failed!\n");
205 static void send_netlink(struct lananlmsg
*lmsg
)
208 struct sockaddr_nl src_addr
, dest_addr
;
209 struct nlmsghdr
*nlh
;
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
;
224 src_addr
.nl_pid
= getpid();
225 src_addr
.nl_groups
= 0;
227 ret
= bind(sock
, (struct sockaddr
*) &src_addr
, sizeof(src_addr
));
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
));
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
);
254 ret
= sendmsg(sock
, &msg
, 0);
255 if (unlikely(ret
< 0))
256 panic("Cannot send NETLINK message to the kernel!\n");
262 static void do_add(int argc
, char **argv
)
264 struct lananlmsg lmsg
;
265 struct lananlmsg_add
*msg
;
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
));
278 static void do_set(int argc
, char **argv
)
280 struct lananlmsg lmsg
;
281 struct lananlmsg_set
*msg
;
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
));
294 static void do_rm(int argc
, char **argv
)
296 struct lananlmsg lmsg
;
297 struct lananlmsg_rm
*msg
;
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
));
309 static void do_bind(int argc
, char **argv
)
311 struct lananlmsg lmsg
;
312 struct lananlmsg_bind
*msg
;
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
));
325 static void do_unbind(int argc
, char **argv
)
327 struct lananlmsg lmsg
;
328 struct lananlmsg_unbind
*msg
;
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
));
341 static void do_replace(int argc
, char **argv
, int drop
)
343 struct lananlmsg lmsg
;
344 struct lananlmsg_replace
*msg
;
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
));
358 static void do_subscribe(int argc
, char **argv
)
360 struct lananlmsg lmsg
;
361 struct lananlmsg_subscribe
*msg
;
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
));
374 static void do_unsubscribe(int argc
, char **argv
)
376 struct lananlmsg lmsg
;
377 struct lananlmsg_unsubscribe
*msg
;
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
));
390 int main(int argc
, char **argv
)
392 check_for_root_maybe_die();
397 if (!strncmp("help", argv
[0], strlen("help")))
399 else if (!strncmp("version", argv
[0], strlen("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
);