vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

chbind.c (8496B)


      1 // $Id$
      2 
      3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
      4 // based on chbind.cc by Jacques Gelinas
      5 //  
      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)
      9 // any later version.
     10 //  
     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.
     15 //  
     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.
     19 
     20 #ifdef HAVE_CONFIG_H
     21 #  include <config.h>
     22 #endif
     23 
     24 #include "vserver.h"
     25 #include "util.h"
     26 
     27 #include <lib/internal.h>
     28 
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <netdb.h>
     33 #include <sys/socket.h>
     34 #include <sys/ioctl.h>
     35 #include <net/if.h>
     36 #include <unistd.h>
     37 #include <errno.h>
     38 #include <getopt.h>
     39 #include <fcntl.h>
     40 #include <netinet/in.h>
     41 #include <arpa/inet.h>
     42 
     43 #define ENSC_WRAPPERS_PREFIX	"chbind: "
     44 #define ENSC_WRAPPERS_IO	1
     45 #define ENSC_WRAPPERS_UNISTD	1
     46 #define ENSC_WRAPPERS_VSERVER	1
     47 #include "wrappers.h"
     48 
     49 #define CMD_HELP	0x1000
     50 #define CMD_VERSION	0x1001
     51 
     52 #define CMD_SILENT	0x2000
     53 #define CMD_IP		0x2001
     54 #define CMD_BCAST	0x2002
     55 #define CMD_NID		0x2003
     56 
     57 int wrapper_exit_code = 255;
     58 
     59 
     60 static struct option const
     61 CMDLINE_OPTIONS[] = {
     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 },
     68   { 0,0,0,0 }
     69 };
     70 
     71 static void
     72 showHelp(int fd, char const *cmd, int res)
     73 {
     74   WRITE_MSG(fd, "Usage:\n  ");
     75   WRITE_STR(fd, cmd);
     76   WRITE_MSG(fd,
     77 	    " [--silent] [--nid <nid>] [--ip <ip_num>[/<mask>]] [--bcast <broadcast>] [--] <commands> <args>*\n\n"
     78 	    "Please report bugs to " PACKAGE_BUGREPORT "\n");
     79 
     80   exit(res);
     81 }
     82 
     83 static void
     84 showVersion()
     85 {
     86   WRITE_MSG(1,
     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);
     91   exit(0);
     92 }
     93 
     94 /*
     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.
     98 
     99 	Return != 0 if the device exist.
    100 */
    101 static bool
    102 existsDevice(char const *dev_raw)
    103 {
    104   size_t	buf_size=8192;
    105   char		dev[strlen(dev_raw)+2];
    106 
    107   strcpy(dev, dev_raw);
    108   strcat(dev, ":");
    109   for (;;) {
    110     char	buf[buf_size];
    111     char *	pos;
    112     bool	too_small;
    113     int		fd=open("/proc/net/dev", O_RDONLY);
    114     
    115     if (fd==-1) return false;
    116     too_small = EreadAll(fd, buf, buf_size);
    117     close(fd);
    118 
    119     if (too_small) {
    120       buf_size *= 2;
    121       continue;
    122     }
    123 
    124     pos = strstr(buf, dev);
    125     return (pos && (pos==buf || pos[-1]==' ' || pos[-1]=='\n'));
    126   }
    127 }
    128 
    129 static int ifconfig_ioctl(
    130 	int fd,
    131 	const char *ifname,
    132 	int cmd,
    133 	struct ifreq *ifr)
    134 {
    135 	strcpy(ifr->ifr_name, ifname);
    136 	return ioctl(fd, cmd,ifr);
    137 }
    138 
    139 /*
    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.
    143 */
    144 int ifconfig_getaddr (
    145 	const char *ifname,
    146 	uint32_t *addr,
    147 	uint32_t *mask,
    148 	uint32_t *bcast)
    149 {
    150 	int ret = -1;
    151 	if (existsDevice(ifname)){
    152 		int skfd = socket(AF_INET, SOCK_DGRAM, 0);
    153 		*addr = 0;
    154 		*bcast = 0xffffffff;
    155 		if (skfd != -1){
    156 			struct ifreq ifr;
    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;
    160 				ret = 0;
    161 			}
    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;
    165 				ret = 0;
    166 			}
    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;
    170 				ret = 0;
    171 			}
    172 			close (skfd);
    173 		}
    174 	}
    175 	return ret;
    176 }
    177 
    178 static void
    179 readIP(char const *str, struct vc_ip_mask_pair *ip, uint32_t *bcast)
    180 {
    181   if (ifconfig_getaddr(str, &ip->ip, &ip->mask, bcast)==-1) {
    182     char		*pt;
    183     char		tmpopt[strlen(str)+1];
    184     struct hostent	*h;
    185 
    186     strcpy(tmpopt,str);
    187     pt = strchr(tmpopt,'/');
    188     
    189     if (pt==0)
    190       ip->mask = ntohl(0xffffff00);
    191     else {
    192       *pt++ = '\0';
    193 
    194       // Ok, we have a network size, not a netmask
    195       if (strchr(pt,'.')==0) {
    196 	int		sz = atoi(pt);
    197 	;
    198 	for (ip->mask = 0; sz>0; --sz) {
    199 	  ip->mask >>= 1;
    200 	  ip->mask  |= 0x80000000;
    201 	}
    202 	ip->mask = ntohl(ip->mask);
    203       }
    204       else { 
    205 	struct hostent *h = gethostbyname (pt);
    206 	if (h==0) {
    207 	  WRITE_MSG(2, "Invalid netmask '");
    208 	  WRITE_STR(2, pt);
    209 	  WRITE_MSG(2, "'\n");
    210 	  exit(wrapper_exit_code);
    211 	}
    212 
    213 	memcpy (&ip->mask, h->h_addr, sizeof(ip->mask));
    214       }
    215     }
    216 
    217     h = gethostbyname (tmpopt);
    218     if (h==0) {
    219       WRITE_MSG(2, "Invalid IP number or host name '");
    220       WRITE_STR(2, tmpopt);
    221       WRITE_MSG(2, "'\n");
    222       exit(wrapper_exit_code);
    223     }
    224 
    225     memcpy (&ip->ip, h->h_addr,sizeof(ip->ip));
    226   }
    227 }
    228 
    229 static void
    230 readBcast(char const *str, uint32_t *bcast)
    231 {
    232   uint32_t	tmp;
    233   if (ifconfig_getaddr(str, &tmp, &tmp, bcast)==-1){
    234     struct hostent *h = gethostbyname (str);
    235     if (h==0){
    236       WRITE_MSG(2, "Invalid broadcast number '");
    237       WRITE_STR(2, optarg);
    238       WRITE_MSG(2, "'\n");
    239       exit(wrapper_exit_code);
    240     }
    241     memcpy (bcast, h->h_addr,sizeof(*bcast));
    242   }
    243 }
    244 
    245 int main (int argc, char *argv[])
    246 {
    247   size_t const			nb_ipv4root = vc_get_nb_ipv4root();
    248   bool				is_silent   = false;
    249   struct vc_ip_mask_pair	ips[nb_ipv4root];
    250   size_t			nbaddrs = 0;
    251   uint32_t			bcast   = 0xffffffff;
    252   
    253   while (1) {
    254     int		c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
    255     if (c==-1) break;
    256 
    257     switch (c) {
    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;
    263       case CMD_IP		:
    264 	if (nbaddrs>=nb_ipv4root) {
    265 	  WRITE_MSG(2, "Too many IP numbers, max 16\n");
    266 	  exit(wrapper_exit_code);
    267 	}
    268 	readIP(optarg, ips+nbaddrs, &bcast);
    269 	++nbaddrs;
    270 	break;
    271       default		:
    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);
    276 	break;
    277     }
    278   }
    279 
    280   if (optind==argc) {
    281     WRITE_MSG(2, "No command given; try '--help' for more information\n");
    282     exit(wrapper_exit_code);
    283   }
    284   
    285 #if !defined(VC_ENABLE_API_COMPAT) && !defined(VC_ENABLE_API_LEGACY)
    286 #  warning building a dummy chbind-compat with no available APIs
    287 #endif
    288   
    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);
    293   }
    294 #else
    295   {
    296     WRITE_MSG(2, "chbind: kernel does not provide network isolation\n");
    297     exit(wrapper_exit_code);
    298   }
    299 #endif
    300 
    301   if (!is_silent) {
    302     size_t		i;
    303     
    304     WRITE_MSG(1, "ipv4root is now");
    305     for (i=0; i<nbaddrs; ++i) {
    306       WRITE_MSG(1, " ");
    307       WRITE_STR(1, inet_ntoa(*reinterpret_cast(struct in_addr *)(&ips[i].ip)));
    308     }
    309     WRITE_MSG(1, "\n");
    310   }
    311 
    312   Eexecvp (argv[optind],argv+optind);
    313   return EXIT_SUCCESS;
    314 }
    315 
    316 #ifdef ENSC_TESTSUITE
    317 #include <assert.h>
    318 
    319 void test()
    320 {
    321   struct vc_ip_mask_pair	ip;
    322   uint32_t			bcast;
    323 
    324   bcast = 0;
    325   readIP("1.2.3.4", &ip, &bcast);
    326   assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffffff00) && bcast==0);
    327 
    328   readIP("1.2.3.4/8", &ip, &bcast);
    329   assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xff000000) && bcast==0);
    330 
    331   readIP("1.2.3.4/255.255.0.0", &ip, &bcast);
    332   assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffff0000) && bcast==0);
    333 
    334   readIP("localhost", &ip, &bcast);
    335   assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xffffff00) && bcast==0);
    336 
    337 #if 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));
    341   }
    342 #endif
    343 }
    344 #endif