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