include <config.h>
[util-vserver.git] / util-vserver / src / chbind.c
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 <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <sys/ioctl.h>
30 #include <netinet/in.h>
31 #include <net/if.h>
32 #include <unistd.h>
33 #include <errno.h>
34
35 #include "vserver.h"
36
37 static void usage()
38 {
39         fprintf (stderr,"chbind version %s\n",VERSION);
40         fprintf (stderr,"chbind [ --silent ] [ --ip ip_num[/mask] ] [ --bcast broadcast ] command argument\n");
41         exit (-1);
42 }
43
44 /*
45         Check if a network device exist in /proc/net/dev.
46         This is used because ifconfig_ioctl triggers modprobe if requesting
47         information about non existant devices.
48
49         Return != 0 if the device exist.
50 */
51 static int chbind_devexist (const char *dev)
52 {
53         int ret = 0;
54         FILE *fin = fopen ("/proc/net/dev","r");
55         if (fin != NULL){
56                 int len = strlen(dev);
57                 char buf[1000];
58                 fgets(buf,sizeof(buf)-1,fin);   // Skip one line
59                 while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
60                         const char *pt = strstr(buf,dev);
61                         if (pt != NULL && pt[len] == ':'){
62                                 ret = 1;
63                                 break;
64                         }
65                 }
66                 fclose (fin);
67         }
68         return ret;
69 }
70
71
72 static int ifconfig_ioctl(
73         int fd,
74         const char *ifname,
75         int cmd,
76         struct ifreq *ifr)
77 {
78         strcpy(ifr->ifr_name, ifname);
79         return ioctl(fd, cmd,ifr);
80 }
81
82 /*
83         Fetch the IP number of an interface from the kernel.
84         Assume the device is already available in the kernel
85         Return -1 if any error.
86 */
87 int ifconfig_getaddr (
88         const char *ifname,
89         unsigned long *addr,
90         unsigned long *mask,
91         unsigned long *bcast)
92 {
93         int ret = -1;
94         if (chbind_devexist(ifname)){
95                 int skfd = socket(AF_INET, SOCK_DGRAM, 0);
96                 *addr = 0;
97                 *bcast = 0xffffffff;
98                 if (skfd != -1){
99                         struct ifreq ifr;
100                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, &ifr) >= 0){
101                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
102                                 *addr = sin->sin_addr.s_addr;
103                                 ret = 0;
104                         }
105                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFNETMASK, &ifr) >= 0){
106                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
107                                 *mask = sin->sin_addr.s_addr;
108                                 ret = 0;
109                         }
110                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFBRDADDR, &ifr) >= 0){
111                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
112                                 *bcast = sin->sin_addr.s_addr;
113                                 ret = 0;
114                         }
115                         close (skfd);
116                 }
117         }
118         return ret;
119 }
120
121
122
123
124 int main (int argc, char *argv[])
125 {
126         int ret = -1;
127         int silent = 0;
128         int i;
129         unsigned long addrs[16],masks[16];
130         int nbaddrs = 0;
131         unsigned long bcast = 0xffffffff;
132         for (i=1; i<argc; i++){
133                 const char *arg = argv[i];
134                 const char *opt = argv[i+1];
135                 if (strcmp(arg,"--ip")==0){
136                         unsigned long addr,mask;
137                         if (nbaddrs == 16){
138                                 fprintf (stderr,"Too many IP numbers, max 16, ignored\n");
139
140                         }else if (ifconfig_getaddr(opt,&addr,&mask,&bcast)==-1){
141                                 unsigned long mask = 0x00ffffff;
142                                 const char *pt = strchr(opt,'/');
143                                 char tmpopt[strlen(opt)+1];
144                                 struct hostent *h;
145                                 
146                                 if (pt != NULL){
147                                         strcpy (tmpopt,opt);
148                                         tmpopt[pt-opt] = '\0';
149                                         opt = tmpopt;
150                                         pt++;
151                                         if (strchr(pt,'.')==NULL){
152                                                 // Ok, we have a network size, not a netmask
153                                                 int size = atoi(pt);
154                                                 int i;
155                                                 mask = 0;
156                                                 for (i=0; i<size; i++){
157                                                         mask = mask >> 1;
158                                                         mask |= 0x80000000;
159                                                 }
160                                                 mask = ntohl(mask);
161                                         }else{
162                                                 struct hostent *h = gethostbyname (pt);
163                                                 if (h != NULL){
164                                                         memcpy (&mask,h->h_addr,sizeof(mask));
165                                                 }else{
166                                                         fprintf (stderr,"Invalid netmask: %s\n",pt);
167                                                         usage();
168                                                 }
169                                         }
170                                                         
171                                 }
172
173                                 h = gethostbyname (opt);
174                                 if (h == NULL){
175                                         fprintf (stderr,"Invalid IP number or host name: %s\n",opt);
176                                         usage();
177                                 }else{
178                                         memcpy (&addr,h->h_addr,sizeof(addr));
179                                         masks[nbaddrs] = mask;
180                                         addrs[nbaddrs++] = addr;
181                                 }
182                         }else{
183                                 masks[nbaddrs] = mask;
184                                 addrs[nbaddrs++] = addr;
185                         }
186                         i++;
187                 }else if (strcmp(arg,"--bcast")==0){
188                         unsigned long tmp;
189                         if (ifconfig_getaddr(opt,&tmp,&tmp,&bcast)==-1){
190                                 struct hostent *h = gethostbyname (opt);
191                                 if (h == NULL){
192                                         fprintf (stderr,"Invalid broadcast number: %s\n",opt);
193                                         usage();
194                                 }else{
195                                         memcpy (&bcast,h->h_addr,sizeof(bcast));
196                                 }
197                         }
198                         i++;
199                 }else if (strcmp(arg,"--silent")==0){
200                         silent = 1;
201                 }else{
202                         break;
203                 }
204         }
205         if (i == argc){
206                 usage();
207         }else if (argv[i][0] == '-'){
208                 usage();
209         }else{
210                 if (call_set_ipv4root(addrs,nbaddrs,bcast,masks)==0){
211                         if (!silent){
212                                 int i;
213                                 printf ("ipv4root is now");
214                                 for (i=0; i<nbaddrs; i++){
215                                         unsigned long hostaddr = ntohl(addrs[i]);
216                                         printf (" %ld.%ld.%ld.%ld"
217                                                 ,hostaddr>>24
218                                                 ,(hostaddr>>16)&0xff
219                                                 ,(hostaddr>>8)&0xff
220                                                 ,hostaddr &0xff);
221                                 }
222                                 printf ("\n");
223                         }
224                         execvp (argv[i],argv+i);
225                         fprintf (stderr,"Can't exec %s (%s)\n",argv[i],strerror(errno));
226                 }else{
227                         fprintf (stderr,"Can't set the ipv4 root (%s)\n",strerror(errno));
228                 }
229         }
230         return ret;
231 }
232
233