3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // Copyright (C) 2006 Daniel Hokka Zakrisson <daniel@hozac.com>
5 // based on chbind.cc by Jacques Gelinas
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2, or (at your option)
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include <lib/internal.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
44 #define ENSC_WRAPPERS_PREFIX "naddress: "
45 #define ENSC_WRAPPERS_IO 1
46 #define ENSC_WRAPPERS_UNISTD 1
47 #define ENSC_WRAPPERS_VSERVER 1
50 #define CMD_HELP 0x1000
51 #define CMD_VERSION 0x1001
53 #define CMD_SILENT 0x2000
54 #define CMD_NID 0x2001
55 #define CMD_ADD 0x2002
56 #define CMD_REMOVE 0x2003
58 #define CMD_BCAST 0x2011
60 int wrapper_exit_code = 255;
63 static struct option const
65 { "help", no_argument, 0, CMD_HELP },
66 { "version", no_argument, 0, CMD_VERSION },
67 { "silent", no_argument, 0, CMD_SILENT },
68 { "add", no_argument, 0, CMD_ADD },
69 { "remove", no_argument, 0, CMD_REMOVE },
70 { "nid", required_argument, 0, CMD_NID },
71 { "ip", required_argument, 0, CMD_IP },
72 { "bcast", required_argument, 0, CMD_BCAST },
90 showHelp(int fd, char const *cmd, int res)
92 WRITE_MSG(fd, "Usage:\n ");
95 " [--silent] [--nid <nid>] [--ip <ip_num>[/<mask>]] [--bcast <broadcast>] [--] <commands> <args>*\n\n"
96 "Please report bugs to " PACKAGE_BUGREPORT "\n");
105 "naddress " VERSION " -- bind to an ip and execute a program\n"
106 "This program is part of " PACKAGE_STRING "\n\n"
107 "Copyright (C) 2003,2004 Enrico Scholz\n"
108 "Copyright (C) 2006 Daniel Hokka Zakrisson\n"
109 VERSION_COPYRIGHT_DISCLAIMER);
114 Check if a network device exist in /proc/net/dev.
115 This is used because ifconfig_ioctl triggers modprobe if requesting
116 information about non existant devices.
118 Return != 0 if the device exist.
121 existsDevice(char const *dev_raw)
123 size_t buf_size=8192;
124 char dev[strlen(dev_raw)+2];
126 strcpy(dev, dev_raw);
132 int fd=open("/proc/net/dev", O_RDONLY);
134 if (fd==-1) return false;
135 too_small = EreadAll(fd, buf, buf_size);
143 pos = strstr(buf, dev);
144 return (pos && (pos==buf || pos[-1]==' ' || pos[-1]=='\n'));
148 static int ifconfig_ioctl(
154 strcpy(ifr->ifr_name, ifname);
155 return ioctl(fd, cmd, ifr);
159 Fetch the IP number of an interface from the kernel.
160 Assume the device is already available in the kernel
161 Return -1 if any error.
163 int ifconfig_getaddr (
170 if (existsDevice(ifname)){
171 int skfd = socket(AF_INET, SOCK_DGRAM, 0);
174 if (addr != NULL && ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, &ifr) >= 0){
175 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
176 *addr = sin->sin_addr.s_addr;
179 if (mask != NULL && ifconfig_ioctl(skfd,ifname,SIOCGIFNETMASK, &ifr) >= 0){
180 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
181 *mask = sin->sin_addr.s_addr;
184 if (bcast != NULL && ifconfig_ioctl(skfd,ifname,SIOCGIFBRDADDR, &ifr) >= 0){
185 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
186 *bcast = sin->sin_addr.s_addr;
196 convertAddress(const char *str, vc_net_nx_type *type, void *dst)
199 if (type) *type = vcNET_IPV4;
200 ret = inet_pton(AF_INET, str, dst);
202 if (type) *type = vcNET_IPV6;
203 ret = inet_pton(AF_INET6, str, dst);
205 return ret > 0 ? 0 : -1;
209 readIP(char const *str, struct vc_ips **ips)
211 if (ifconfig_getaddr(str, &(*ips)->a.ip[0], &(*ips)->a.mask[0], NULL)==-1) {
213 char tmpopt[strlen(str)+1];
214 uint32_t *mask = (*ips)->a.mask;
217 pt = strchr(tmpopt,'/');
221 if (convertAddress(tmpopt, &(*ips)->a.type, (*ips)->a.ip) == -1) {
222 WRITE_MSG(2, "Invalid IP number '");
223 WRITE_STR(2, tmpopt);
225 exit(wrapper_exit_code);
229 switch ((*ips)->a.type) {
231 mask[0] = htonl(0xffffff00);
240 // Ok, we have a network size, not a netmask
241 if (strchr(pt,'.')==0 && strchr(pt,':')==0) {
243 switch ((*ips)->a.type) {
245 mask[0] = htonl((1 << sz) - 1);
254 if (convertAddress(pt, NULL, &(*ips)->a.mask) == -1) {
255 WRITE_MSG(2, "Invalid netmask '");
258 exit(wrapper_exit_code);
264 (*ips)->a.type = vcNET_IPV4;
267 (*ips)->next = calloc(1, sizeof(struct vc_ips));
272 readBcast(char const *str, struct vc_ips **ips)
275 if (ifconfig_getaddr(str, NULL, NULL, &bcast)==-1){
276 if (convertAddress(str, NULL, &bcast) == -1) {
277 WRITE_MSG(2, "Invalid broadcast number '");
278 WRITE_STR(2, optarg);
280 exit(wrapper_exit_code);
283 (*ips)->a.ip[0] = bcast;
285 (*ips)->a.type = vcNET_IPV4B;
286 (*ips)->next = calloc(1, sizeof(struct vc_ips));
291 tellAddress(struct vc_net_nx *addr, bool silent)
296 if (inet_ntop(addr->type == vcNET_IPV6 ? AF_INET6 : AF_INET,
297 &addr->ip, buf, sizeof(buf)) == NULL) {
298 WRITE_MSG(1, " <conversion failed>");
306 doit(struct Arguments *args)
310 if (!args->is_silent)
311 WRITE_MSG(1, "Adding");
312 for (ips = &args->head; ips->next; ips = ips->next) {
313 tellAddress(&ips->a, args->is_silent);
314 if (vc_net_add(args->nid, &ips->a) != (int)ips->a.count) {
315 perror(ENSC_WRAPPERS_PREFIX "vc_net_add()");
316 exit(wrapper_exit_code);
319 if (!args->is_silent)
322 else if (args->do_remove) {
323 if (!args->is_silent)
324 WRITE_MSG(1, "Removing");
325 for (ips = &args->head; ips->next; ips = ips->next) {
326 tellAddress(&ips->a, args->is_silent);
327 if (vc_net_remove(args->nid, &ips->a) != (int)ips->a.count) {
328 perror(ENSC_WRAPPERS_PREFIX "vc_net_remove()");
329 exit(wrapper_exit_code);
332 if (!args->is_silent)
337 int main (int argc, char *argv[])
339 struct Arguments args = {
344 .head = { .next = NULL },
346 struct vc_ips *ips = &args.head;
349 int c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
353 case CMD_HELP : showHelp(1, argv[0], 0);
354 case CMD_VERSION : showVersion();
355 case CMD_SILENT : args.is_silent = true; break;
356 case CMD_BCAST : readBcast(optarg, &ips); break;
357 case CMD_NID : args.nid = Evc_nidopt2nid(optarg,true); break;
358 case CMD_ADD : args.do_add = true; break;
359 case CMD_REMOVE : args.do_remove = true; break;
360 case CMD_IP : readIP(optarg, &ips); break;
362 WRITE_MSG(2, "Try '");
363 WRITE_STR(2, argv[0]);
364 WRITE_MSG(2, " --help\" for more information.\n");
365 exit(wrapper_exit_code);
370 if (args.nid == VC_NOCTX) args.nid = Evc_get_task_nid(0);
372 if (!args.do_add && !args.do_remove) {
373 WRITE_MSG(2, "No operation specified; try '--help' for more information\n");
374 exit(wrapper_exit_code);
376 else if (args.do_add && args.do_remove) {
377 WRITE_MSG(2, "Multiple operations specified; try '--help' for more information\n");
378 exit(wrapper_exit_code);
384 Eexecvp (argv[optind],argv+optind);
388 #ifdef ENSC_TESTSUITE
393 struct vc_ip_mask_pair ip;
397 readIP("1.2.3.4", &ip, &bcast);
398 assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffffff00) && bcast==0);
400 readIP("1.2.3.4/8", &ip, &bcast);
401 assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xff000000) && bcast==0);
403 readIP("1.2.3.4/255.255.0.0", &ip, &bcast);
404 assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffff0000) && bcast==0);
406 readIP("localhost", &ip, &bcast);
407 assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xffffff00) && bcast==0);
410 if (ifconfig_getaddr("lo", &tmp, &tmp, &tmp)!=-1) {
411 readIP("lo", &ip, &bcast);
412 assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xff000000) && bcast==ntohl(0x7fffffff));