3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on chbind.cc by Jacques Gelinas
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include <lib/internal.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
43 #define ENSC_WRAPPERS_PREFIX "chbind: "
44 #define ENSC_WRAPPERS_IO 1
45 #define ENSC_WRAPPERS_UNISTD 1
46 #define ENSC_WRAPPERS_VSERVER 1
49 #define CMD_HELP 0x1000
50 #define CMD_VERSION 0x1001
52 #define CMD_SILENT 0x2000
54 #define CMD_BCAST 0x2002
55 #define CMD_NID 0x2003
57 int wrapper_exit_code = 255;
60 static struct option const
62 { "help", no_argument, 0, CMD_HELP },
63 { "version", no_argument, 0, CMD_VERSION },
64 { "silent", no_argument, 0, CMD_SILENT },
65 { "ip", required_argument, 0, CMD_IP },
66 { "bcast", required_argument, 0, CMD_BCAST },
67 { "nid", required_argument, 0, CMD_NID },
72 showHelp(int fd, char const *cmd, int res)
74 WRITE_MSG(fd, "Usage:\n ");
77 " [--silent] [--nid <nid>] [--ip <ip_num>[/<mask>]] [--bcast <broadcast>] [--] <commands> <args>*\n\n"
78 "Please report bugs to " PACKAGE_BUGREPORT "\n");
87 "chbind " VERSION " -- bind to an ip and execute a program\n"
88 "This program is part of " PACKAGE_STRING "\n\n"
89 "Copyright (C) 2003,2004 Enrico Scholz\n"
90 VERSION_COPYRIGHT_DISCLAIMER);
95 Check if a network device exist in /proc/net/dev.
96 This is used because ifconfig_ioctl triggers modprobe if requesting
97 information about non existant devices.
99 Return != 0 if the device exist.
102 existsDevice(char const *dev_raw)
104 size_t buf_size=8192;
105 char dev[strlen(dev_raw)+2];
107 strcpy(dev, dev_raw);
113 int fd=open("/proc/net/dev", O_RDONLY);
115 if (fd==-1) return false;
116 too_small = EreadAll(fd, buf, buf_size);
124 pos = strstr(buf, dev);
125 return (pos && (pos==buf || pos[-1]==' ' || pos[-1]=='\n'));
129 static int ifconfig_ioctl(
135 strcpy(ifr->ifr_name, ifname);
136 return ioctl(fd, cmd,ifr);
140 Fetch the IP number of an interface from the kernel.
141 Assume the device is already available in the kernel
142 Return -1 if any error.
144 int ifconfig_getaddr (
151 if (existsDevice(ifname)){
152 int skfd = socket(AF_INET, SOCK_DGRAM, 0);
157 if (ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, &ifr) >= 0){
158 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
159 *addr = sin->sin_addr.s_addr;
162 if (ifconfig_ioctl(skfd,ifname,SIOCGIFNETMASK, &ifr) >= 0){
163 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
164 *mask = sin->sin_addr.s_addr;
167 if (ifconfig_ioctl(skfd,ifname,SIOCGIFBRDADDR, &ifr) >= 0){
168 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
169 *bcast = sin->sin_addr.s_addr;
179 readIP(char const *str, struct vc_ip_mask_pair *ip, uint32_t *bcast)
181 if (ifconfig_getaddr(str, &ip->ip, &ip->mask, bcast)==-1) {
183 char tmpopt[strlen(str)+1];
187 pt = strchr(tmpopt,'/');
190 ip->mask = ntohl(0xffffff00);
194 // Ok, we have a network size, not a netmask
195 if (strchr(pt,'.')==0) {
198 for (ip->mask = 0; sz>0; --sz) {
200 ip->mask |= 0x80000000;
202 ip->mask = ntohl(ip->mask);
205 struct hostent *h = gethostbyname (pt);
207 WRITE_MSG(2, "Invalid netmask '");
210 exit(wrapper_exit_code);
213 memcpy (&ip->mask, h->h_addr, sizeof(ip->mask));
217 h = gethostbyname (tmpopt);
219 WRITE_MSG(2, "Invalid IP number or host name '");
220 WRITE_STR(2, tmpopt);
222 exit(wrapper_exit_code);
225 memcpy (&ip->ip, h->h_addr,sizeof(ip->ip));
230 readBcast(char const *str, uint32_t *bcast)
233 if (ifconfig_getaddr(str, &tmp, &tmp, bcast)==-1){
234 struct hostent *h = gethostbyname (str);
236 WRITE_MSG(2, "Invalid broadcast number '");
237 WRITE_STR(2, optarg);
239 exit(wrapper_exit_code);
241 memcpy (bcast, h->h_addr,sizeof(*bcast));
245 int main (int argc, char *argv[])
247 size_t const nb_ipv4root = vc_get_nb_ipv4root();
248 bool is_silent = false;
249 struct vc_ip_mask_pair ips[nb_ipv4root];
251 uint32_t bcast = 0xffffffff;
254 int c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
258 case CMD_HELP : showHelp(1, argv[0], 0);
259 case CMD_VERSION : showVersion();
260 case CMD_SILENT : is_silent = true; break;
261 case CMD_BCAST : readBcast(optarg, &bcast); break;
262 case CMD_NID : WRITE_MSG(2, "WARNING: --nid is not supported by this version\n"); break;
264 if (nbaddrs>=nb_ipv4root) {
265 WRITE_MSG(2, "Too many IP numbers, max 16\n");
266 exit(wrapper_exit_code);
268 readIP(optarg, ips+nbaddrs, &bcast);
272 WRITE_MSG(2, "Try '");
273 WRITE_STR(2, argv[0]);
274 WRITE_MSG(2, " --help' for more information.\n");
275 exit(wrapper_exit_code);
281 WRITE_MSG(2, "No command given; try '--help' for more information\n");
282 exit(wrapper_exit_code);
285 #if !defined(VC_ENABLE_API_COMPAT) && !defined(VC_ENABLE_API_LEGACY)
286 # warning building a dummy chbind-compat with no available APIs
289 #if defined(VC_ENABLE_API_COMPAT) || defined(VC_ENABLE_API_LEGACY)
290 if (vc_set_ipv4root(bcast,nbaddrs,ips)!=0) {
291 perror("chbind: vc_set_ipv4root()");
292 exit(wrapper_exit_code);
296 WRITE_MSG(2, "chbind: kernel does not provide network isolation\n");
297 exit(wrapper_exit_code);
304 WRITE_MSG(1, "ipv4root is now");
305 for (i=0; i<nbaddrs; ++i) {
307 WRITE_STR(1, inet_ntoa(*reinterpret_cast(struct in_addr *)(&ips[i].ip)));
312 Eexecvp (argv[optind],argv+optind);
316 #ifdef ENSC_TESTSUITE
321 struct vc_ip_mask_pair ip;
325 readIP("1.2.3.4", &ip, &bcast);
326 assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffffff00) && bcast==0);
328 readIP("1.2.3.4/8", &ip, &bcast);
329 assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xff000000) && bcast==0);
331 readIP("1.2.3.4/255.255.0.0", &ip, &bcast);
332 assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffff0000) && bcast==0);
334 readIP("localhost", &ip, &bcast);
335 assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xffffff00) && bcast==0);
338 if (ifconfig_getaddr("lo", &tmp, &tmp, &tmp)!=-1) {
339 readIP("lo", &ip, &bcast);
340 assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xff000000) && bcast==ntohl(0x7fffffff));