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> 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");
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");
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");
155 static void do_preload(int argc
, char **argv
)
158 char path
[256], file
[320], cmd
[512], *env
;
162 panic("Invalid args!\n");
164 memset(cmd
, 0, sizeof(cmd
));
165 env
= getenv("FBCFG_PRELOAD_DIR");
167 snprintf(cmd
, sizeof(cmd
), "modprobe %s", argv
[0]);
168 cmd
[sizeof(cmd
) - 1] = 0;
170 ret
= WEXITSTATUS(ret
);
172 panic("Preload failed!\n");
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
);
185 panic("Module does not exist!\n");
186 ret
= fstat(fd
, &sb
);
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");
196 snprintf(cmd
, sizeof(cmd
), "insmod %s", file
);
197 cmd
[sizeof(cmd
) - 1] = 0;
199 ret
= WEXITSTATUS(ret
);
201 panic("Preload failed!\n");
204 static void send_netlink(struct lananlmsg
*lmsg
)
207 struct sockaddr_nl src_addr
, dest_addr
;
208 struct nlmsghdr
*nlh
;
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
;
223 src_addr
.nl_pid
= getpid();
224 src_addr
.nl_groups
= 0;
226 ret
= bind(sock
, (struct sockaddr
*) &src_addr
, sizeof(src_addr
));
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
));
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
);
253 ret
= sendmsg(sock
, &msg
, 0);
254 if (unlikely(ret
< 0))
255 panic("Cannot send NETLINK message to the kernel!\n");
261 static void do_add(int argc
, char **argv
)
263 struct lananlmsg lmsg
;
264 struct lananlmsg_add
*msg
;
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
));
277 static void do_set(int argc
, char **argv
)
279 struct lananlmsg lmsg
;
280 struct lananlmsg_set
*msg
;
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
));
293 static void do_rm(int argc
, char **argv
)
295 struct lananlmsg lmsg
;
296 struct lananlmsg_rm
*msg
;
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
));
308 static void do_bind(int argc
, char **argv
)
310 struct lananlmsg lmsg
;
311 struct lananlmsg_bind
*msg
;
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
));
324 static void do_unbind(int argc
, char **argv
)
326 struct lananlmsg lmsg
;
327 struct lananlmsg_unbind
*msg
;
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
));
340 static void do_replace(int argc
, char **argv
, int drop
)
342 struct lananlmsg lmsg
;
343 struct lananlmsg_replace
*msg
;
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
));
357 static void do_subscribe(int argc
, char **argv
)
359 struct lananlmsg lmsg
;
360 struct lananlmsg_subscribe
*msg
;
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
));
373 static void do_unsubscribe(int argc
, char **argv
)
375 struct lananlmsg lmsg
;
376 struct lananlmsg_unsubscribe
*msg
;
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
));
389 int main(int argc
, char **argv
)
391 check_for_root_maybe_die();
396 if (!strncmp("help", argv
[0], strlen("help")))
398 else if (!strncmp("version", argv
[0], strlen("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
);