fix some logic flaws
[util-vserver.git] / src / ifspec.c
1 // $Id: ifspec.c 965 2004-02-20 16:59:40Z ensc $
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on ifspec.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 /*
21         Prints the specs of a network device in shell like form
22
23         ADDR=
24         NETMASK=
25         BCAST=
26 */
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <unistd.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <netinet/in.h>
39 #include <net/if.h>
40
41 static void usage()
42 {
43         fprintf (stderr,"ifspec version %s\n",VERSION);
44         fprintf (stderr
45                 ,"ifspec network-device [ ipaddr netmask broadcast ]\n"
46                  "prints device specification in a shell usable way\n");
47         exit (-1);
48 }
49
50 static int ifconfig_ioctl(
51         int fd,
52         const char *ifname,
53         int cmd,
54         struct ifreq *ifr)
55 {
56         strcpy(ifr->ifr_name, ifname);
57         return ioctl(fd, cmd,ifr);
58 }
59
60 static unsigned long ip_cnv (const char *str)
61 {
62         const char *start_str = str;
63         unsigned tb[4];
64         int no = 0;
65         unsigned long ret;
66           
67         memset (tb,-1,sizeof(tb));
68         while (*str != '\0' && no < 4){
69                 if (isdigit(*str)){
70                         int val = atoi(str);
71                         if (val > 255) break;
72                         tb[no++] = val;
73                         while (isdigit(*str)) str++;
74                         if (*str == '.'){
75                                 str++;
76                         }else{
77                                 break;
78                         }
79                 }else{
80                         break;
81                 }
82         }
83
84         ret = (tb[0] << 24) | (tb[1]<<16) | (tb[2] << 8) | tb[3];
85         if (no != 4 || *str != '\0'){
86                 fprintf (stderr,"Invalid IP number or netmask: %s\n",start_str);
87                 ret = 0xffffffff;
88         }
89         return ret;
90 }
91
92
93 /*
94         Fetch the IP number of an interface from the kernel.
95         Assume the device is already available in the kernel
96         Return -1 if any error.
97 */
98 int ifconfig_print (
99         const char *ifname,
100         const char *addrstr,
101         const char *maskstr,
102         const char *bcaststr)
103 {
104         int ret = -1;
105         int skfd = socket(AF_INET, SOCK_DGRAM, 0);
106         if (skfd != -1){
107                 struct ifreq ifr;
108                 struct {
109                         unsigned long addr;
110                         unsigned long mask;
111                 } solved = {0,0};
112                 if (addrstr != NULL && addrstr[0] != '\0'){
113                         printf ("ADDR=%s\n",addrstr);
114                         solved.addr = ip_cnv (addrstr);
115                 }else if (ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, &ifr) >= 0){
116                         struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
117                         unsigned long addr = ntohl(sin->sin_addr.s_addr);
118                         printf ("ADDR=%lu.%lu.%lu.%lu\n"
119                                 ,(addr>>24)&0xff
120                                 ,(addr>>16)&0xff
121                                 ,(addr>>8)&0xff
122                                 ,addr&0xff);
123                         solved.addr = addr;
124                         ret = 0;
125                 }
126                 else {
127                   perror("ifspec: ioctl(SIOCGIFADDR)");
128                 }
129                 
130                 if (maskstr != NULL && maskstr[0] != '\0'){
131                         printf ("NETMASK=%s\n",maskstr);
132                         solved.mask = ip_cnv (maskstr);
133                 }else           if (ifconfig_ioctl(skfd,ifname,SIOCGIFNETMASK, &ifr) >= 0){
134                         struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
135                         unsigned long addr = ntohl(sin->sin_addr.s_addr);
136                         printf ("NETMASK=%lu.%lu.%lu.%lu\n"
137                                 ,(addr>>24)&0xff
138                                 ,(addr>>16)&0xff
139                                 ,(addr>>8)&0xff
140                                 ,addr&0xff);
141                         solved.mask = addr;
142                         ret = 0;
143                 }
144                 else {
145                   perror("ifspec: ioctl(SIOCGIFNETMASK)");
146                 }
147                 
148                 if (bcaststr != NULL && bcaststr[0] != '\0'){
149                         printf ("BCAST=%s\n",bcaststr);
150                 }else if (ifconfig_ioctl(skfd,ifname,SIOCGIFBRDADDR, &ifr) >= 0){
151                         struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
152                         unsigned long addr = ntohl(sin->sin_addr.s_addr);
153                         printf ("BCAST=%lu.%lu.%lu.%lu\n"
154                                 ,(addr>>24)&0xff
155                                 ,(addr>>16)&0xff
156                                 ,(addr>>8)&0xff
157                                 ,addr&0xff);
158                         ret = 0;
159                 }else if (solved.addr!=0 && solved.mask!=0) {
160                         // Can't get it from the kernel, compute it from the IP
161                         // and the netmask
162                         unsigned long addr = (solved.addr & solved.mask)
163                                 | ~solved.mask;
164                         printf ("BCAST=%lu.%lu.%lu.%lu\n"
165                                 ,(addr>>24)&0xff
166                                 ,(addr>>16)&0xff
167                                 ,(addr>>8)&0xff
168                                 ,addr&0xff);
169                         
170                 }
171                 close (skfd);
172         }
173         return ret;
174 }
175
176
177 int main (int argc, char *argv[])
178 {
179         int ret = -1;
180         if (argc < 2){
181                 usage();
182         }else{
183                 const char *addrstr = argc >= 3 ? argv[2] : NULL;
184                 const char *maskstr = argc >= 4 ? argv[3] : NULL;
185                 const char *bcaststr = argc >= 5 ? argv[4] : NULL;
186                 ret = ifconfig_print (argv[1],addrstr,maskstr,bcaststr);
187         }
188         return ret;
189 }
190
191
192