8d97d1b992886bab3722a7c50c1ab8cd0dca5049
[tpg/acess2.git] / Usermode / Applications / ifconfig_src / main.c
1 /*
2  * Acess2 IFCONFIG command
3  */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <acess/sys.h>
9 #include <net.h>
10
11 // === CONSTANTS ===
12 #define FILENAME_MAX    255
13 #define IPSTACK_ROOT    "/Devices/ip"
14
15 // TODO: Move this to a header
16 #define ntohs(v)        (((v&0xFF)<<8)|((v>>8)&0xFF))
17
18 // === PROTOTYPES ===
19 void    PrintUsage(const char *ProgName);
20 void    DumpInterfaces(void);
21 void    DumpRoutes(void);
22 void    DumpInterface(const char *Name);
23 void    DumpRoute(const char *Name);
24  int    AddInterface(const char *Device);
25 void    AddRoute(const char *Interface, void *Dest, int MaskBits, void *NextHop);
26  int    DoAutoConfig(const char *Device);
27  int    SetAddress(int IFNum, const char *Address);
28  int    ParseIPAddres(const char *Address, uint8_t *Dest, int *SubnetBits);
29
30 // === CODE ===
31 /**
32  * \brief Program entrypoint
33  */
34 int main(int argc, char *argv[])
35 {
36          int    ret;
37         
38         // No args, dump interfaces
39         if(argc == 1) {
40                 DumpInterfaces();
41                 return 0;
42         }
43         
44         if( strcmp(argv[1], "routes") == 0 ) {
45                 DumpRoutes();
46                 return 0;
47         }
48         
49         // Add a new interface
50         if( strcmp(argv[1], "add") == 0 ) {
51                 if( argc < 4 ) {
52                         fprintf(stderr, "ERROR: '%s add' requires two arguments, %i passed\n", argv[0], argc-2);
53                         PrintUsage(argv[0]);
54                         return -1;
55                 }
56                 // TODO: Also set the IP address as the usage says it does
57                 ret = AddInterface( argv[2] );
58                 if(ret < 0)     return ret;
59                 ret = SetAddress( ret, argv[3] );
60                 return ret;
61         }
62         
63         // Delete an interface
64         if( strcmp(argv[1], "del") == 0 ) {
65                 if( argc < 3 ) {
66                         fprintf(stderr, "ERROR: '%s del' requires an argument\n", argv[0]);
67                         PrintUsage(argv[0]);
68                         return -1;
69                 }
70                 // TODO:
71         }
72         
73         // Autoconfigure an interface
74         // NOTE: Debugging hack (see the function for more details)
75         if( strcmp(argv[1], "autoconf") == 0 ) {
76                 DoAutoConfig(argv[2]);
77                 return 0;
78         }
79         
80         // Print usage instructions
81         PrintUsage(argv[0]);
82         
83         return 0;
84 }
85
86 /**
87  * \brief Print usage instructions
88  */
89 void PrintUsage(const char *ProgName)
90 {
91         fprintf(stderr, "Usage:\n");
92         fprintf(stderr, "    %s add <device> <ip>/<prefix>\n", ProgName);
93         fprintf(stderr, "        Add a new interface listening on <device> with the specified\n");
94         fprintf(stderr, "        address.\n");
95         fprintf(stderr, "    %s del <interface>\n", ProgName);
96         fprintf(stderr, "    %s set <interface> <option> <value>\n", ProgName);
97         fprintf(stderr, "        Set an option on an interface, a list of valid options follows\n");
98         fprintf(stderr, "        gw      IPv4 default gateway\n");
99         fprintf(stderr, "    %s [<interface>]\n", ProgName);
100         fprintf(stderr, "        Print the current interfaces (or only <interface> if passed)\n");
101         fprintf(stderr, "\n");
102         fprintf(stderr, "A note on Acess's IP Stack:\n");
103         fprintf(stderr, "    Each interface corresponds to only one IP address (either IPv4\n");
104         fprintf(stderr, "    or IPv6). A network device can have multiple interfaces bound\n");
105         fprintf(stderr, "    to it, allowing multiple addresses for one network connection\n");
106         fprintf(stderr, "\n");
107 }
108
109 /**
110  * \brief Dump all interfaces
111  */
112 void DumpInterfaces(void)
113 {
114          int    dp;
115         char    filename[FILENAME_MAX+1];
116         
117         dp = open(IPSTACK_ROOT, OPENFLAG_READ);
118         
119         while( readdir(dp, filename) )
120         {
121                 if(filename[0] == '.')  continue;
122                 DumpInterface(filename);
123         }
124         
125         close(dp);
126 }
127
128 /**
129  * \brief Dump all interfaces
130  */
131 void DumpRoutes(void)
132 {
133          int    dp;
134         char    filename[FILENAME_MAX+1];
135         
136         dp = open(IPSTACK_ROOT"/routes", OPENFLAG_READ);
137         
138         while( readdir(dp, filename) )
139         {
140                 if(filename[0] == '.')  continue;
141                 DumpRoute(filename);
142         }
143         
144         close(dp);
145 }
146
147 /**
148  * \brief Dump an interface
149  */
150 void DumpInterface(const char *Name)
151 {
152          int    fd;
153          int    type;
154         char    path[sizeof(IPSTACK_ROOT)+1+FILENAME_MAX+1] = IPSTACK_ROOT"/";
155         
156         strcat(path, Name);
157         
158         fd = open(path, OPENFLAG_READ);
159         if(fd == -1) {
160                 printf("%s:\tUnable to open ('%s')\n", Name, path);
161                 return ;
162         }
163         
164         type = ioctl(fd, 4, NULL);
165         
166         // Ignore -1 values
167         if( type == -1 ) {
168                 return ;
169         }
170         
171         printf("%s:\t", Name);
172         {
173                  int    call_num = ioctl(fd, 3, "get_device");
174                  int    len = ioctl(fd, call_num, NULL);
175                 char    *buf = malloc(len+1);
176                 ioctl(fd, call_num, buf);
177                 printf("'%s'\t", buf);
178                 free(buf);
179         }
180         // Get the address type
181         switch(type)
182         {
183         case 0: // Disabled/Unset
184                 printf("DISABLED\n");
185                 break;
186         case 4: // IPv4
187                 {
188                 uint8_t ip[4];
189                  int    subnet;
190                 printf("IPv4\n");
191                 ioctl(fd, 5, ip);       // Get IP Address
192                 subnet = ioctl(fd, 7, NULL);    // Get Subnet Bits
193                 printf("\tAddress: %i.%i.%i.%i/%i\n", ip[0], ip[1], ip[2], ip[3], subnet);
194                 }
195                 break;
196         case 6: // IPv6
197                 {
198                 uint16_t        ip[8];
199                  int    subnet;
200                 printf("IPv6\n");
201                 ioctl(fd, 5, ip);       // Get IP Address
202                 subnet = ioctl(fd, 7, NULL);    // Get Subnet Bits
203                 printf("\t%x:%x:%x:%x:%x:%x:%x:%x/%i\n",
204                         ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]),
205                         ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]),
206                         subnet);
207                 }
208                 break;
209         default:        // Unknow
210                 printf("UNKNOWN (%i)\n", type);
211                 break;
212         }
213         printf("\n");
214                         
215         close(fd);
216 }
217
218
219 /**
220  * \brief Dump a route
221  */
222 void DumpRoute(const char *Name)
223 {
224          int    fd;
225          int    type;
226         char    path[sizeof(IPSTACK_ROOT)+8+FILENAME_MAX+1] = IPSTACK_ROOT"/routes/";
227         
228         strcat(path, Name);
229         
230         fd = open(path, OPENFLAG_READ);
231         if(fd == -1) {
232                 printf("%s:\tUnable to open ('%s')\n", Name, path);
233                 return ;
234         }
235         
236         type = ioctl(fd, 4, NULL);
237         
238         // Ignore -1 values
239         if( type == -1 ) {
240                 return ;
241         }
242         
243         printf("%s:\t", Name);
244         {
245                  int    call_num = ioctl(fd, 3, "get_interface");
246                  int    len = ioctl(fd, call_num, NULL);
247                 char    *buf = malloc(len+1);
248                 ioctl(fd, call_num, buf);
249                 printf("'%s'\t", buf);
250                 free(buf);
251         }
252         
253         // Get the address type
254         switch(type)
255         {
256         case 0: // Disabled/Unset
257                 printf("DISABLED\n");
258                 break;
259         case 4: // IPv4
260                 {
261                 uint8_t net[4], addr[4];
262                  int    subnet, metric;
263                 printf("IPv4\n");
264                 ioctl(fd, ioctl(fd, 3, "get_network"), net);    // Get Network
265                 ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr);   // Get Gateway/NextHop
266                 subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL);    // Get Subnet Bits
267                 metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL);        // Get Subnet Bits
268                 printf("\tNetwork: %s/%i\n", Net_PrintAddress(4, net), subnet);
269                 printf("\tGateway: %s\n", Net_PrintAddress(4, addr));
270                 printf("\tMetric:  %i\n", metric);
271                 }
272                 break;
273         case 6: // IPv6
274                 {
275                 uint16_t        net[8], addr[8];
276                  int    subnet, metric;
277                 printf("IPv6\n");
278                 ioctl(fd, ioctl(fd, 3, "get_network"), net);    // Get Network
279                 ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr);   // Get Gateway/NextHop
280                 subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL);    // Get Subnet Bits
281                 metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL);        // Get Subnet Bits
282                 printf("\tNetwork: %s/%i\n", Net_PrintAddress(6, net), subnet);
283                 printf("\tGateway: %s\n", Net_PrintAddress(6, addr));
284                 printf("\tMetric:  %i\n", metric);
285                 }
286                 break;
287         default:        // Unknow
288                 printf("UNKNOWN (%i)\n", type);
289                 break;
290         }
291         printf("\n");
292                         
293         close(fd);
294 }
295
296 /**
297  * \brief Create a new interface using the passed device
298  * \param Device        Network device to bind to
299  */
300 int AddInterface(const char *Device)
301 {
302          int    dp, ret;
303         
304         dp = open(IPSTACK_ROOT, OPENFLAG_READ);
305         ret = ioctl(dp, 4, (void*)Device);
306         close(dp);
307         
308         if( ret < 0 ) {
309                 fprintf(stderr, "Unable to add '%s' as a network interface\n", Device);
310                 return -1;
311         }
312         
313         printf("-- Added '"IPSTACK_ROOT"/%i' using device %s\n", ret, Device);
314         
315         return ret;
316 }
317
318 void AddRoute(const char *Interface, void *Dest, int MaskBits, void *NextHop)
319 {
320          int    fd;
321          int    num;
322         char    tmp[sizeof(IPSTACK_ROOT"/routes/") + 5];        // enough for 4 digits
323         
324         // Create route
325         fd = open(IPSTACK_ROOT"/routes", 0);
326         num = ioctl(fd, ioctl(fd, 3, "add_route"), (char*)Interface);
327         close(fd);
328         
329         // Open route
330         sprintf(tmp, IPSTACK_ROOT"/routes/%i", num);
331         fd = open(tmp, 0);
332         
333         ioctl(fd, ioctl(fd, 3, "set_network"), Dest);
334         ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop);
335         ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), &MaskBits);
336         
337         close(fd);
338         
339 }
340
341 /**
342  * \note Debugging HACK!
343  * \brief Autoconfigure the specified device to 10.0.2.55/8 using
344  *        10.0.2.1 as the gateway.
345  */
346 int DoAutoConfig(const char *Device)
347 {
348          int    tmp, fd;
349         char    path[sizeof(IPSTACK_ROOT)+1+4+1];       // /0000
350         uint8_t addr[4] = {10,0,2,55};
351         uint8_t gw[4] = {10,0,2,2};
352          int    subnet = 24;
353         
354         tmp = AddInterface(Device);
355         if( tmp < 0 )   return tmp;
356         
357         sprintf(path, IPSTACK_ROOT"/%i", tmp);
358         
359         fd = open(path, OPENFLAG_READ);
360         if( fd == -1 ) {
361                 fprintf(stderr, "Unable to open '%s'\n", path);
362                 return -1;
363         }
364         
365         tmp = 4;        // IPv4
366         tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
367         if( tmp != 4 ) {
368                 fprintf(stderr, "Error in setting address type (got %i, expected 4)\n", tmp);
369                 return -1;
370         }
371         // Set Address
372         ioctl(fd, ioctl(fd, 3, "set_address"), addr);
373         // Set Subnet
374         ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
375         
376         // Set routes
377         {
378                 uint8_t net[4] = {0,0,0,0};
379                 AddRoute(path + sizeof(IPSTACK_ROOT), addr, subnet, net);       // This interface
380                 AddRoute(path + sizeof(IPSTACK_ROOT), net, 0, gw);      // Gateway
381         }
382         
383         close(fd);
384         
385         printf("Set address to %i.%i.%i.%i/%i (GW: %i.%i.%i.%i)\n",
386                 addr[0], addr[1], addr[2], addr[3],
387                 subnet,
388                 gw[0], gw[1], gw[2], gw[3]);
389         
390         return 0;
391 }
392
393 /**
394  * \brief Set the address on an interface from a textual IP address
395  */
396 int     SetAddress(int IFNum, const char *Address)
397 {
398         uint8_t addr[16];
399          int    type;
400         char    path[sizeof(IPSTACK_ROOT)+1+5+1];       // ip000
401          int    tmp, fd, subnet;
402         
403         // Parse IP Address
404         type = ParseIPAddres(Address, addr, &subnet);
405         if(type == 0) {
406                 fprintf(stderr, "'%s' cannot be parsed as an IP address\n", Address);
407                 return -1;
408         }
409         
410         // Open file
411         sprintf(path, IPSTACK_ROOT"/%i", IFNum);
412         fd = open(path, OPENFLAG_READ);
413         if( fd == -1 ) {
414                 fprintf(stderr, "Unable to open '%s'\n", path);
415                 return -1;
416         }
417         
418         tmp = type;
419         tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
420         if( tmp != type ) {
421                 fprintf(stderr, "Error in setting address type (got %i, expected %i)\n", tmp, type);
422                 close(fd);
423                 return -1;
424         }
425         // Set Address
426         ioctl(fd, ioctl(fd, 3, "set_address"), addr);
427         
428         // Set Subnet
429         ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
430         
431         close(fd);
432         
433         // Dump!
434         //DumpInterface( path+sizeof(IPSTACK_ROOT)+1 );
435         
436         return 0;
437 }
438
439 /**
440  * \brief Parse an IP Address
441  * \return 0 for unknown, 4 for IPv4 and 6 for IPv6
442  */
443 int ParseIPAddres(const char *Address, uint8_t *Dest, int *SubnetBits)
444 {
445         const char      *p = Address;
446         
447         // Check first block
448         while(*p && *p >= '0' && *p <= '9')     p ++;
449         
450         // IPv4?
451         if(*p == '.')
452         {
453                  int    i = 0, j;
454                  int    val;
455                 
456                 for( j = 0; Address[i] && j < 4; j ++ )
457                 {
458                         val = 0;
459                         for( ; '0' <= Address[i] && Address[i] <= '9'; i++ )
460                         {
461                                 val = val*10 + Address[i] - '0';
462                         }
463                         if(val > 255) {
464                                 //printf("val > 255 (%i)\n", val);
465                                 return 0;
466                         }
467                         Dest[j] = val;
468                         
469                         if(Address[i] == '.')
470                                 i ++;
471                 }
472                 if( j != 4 ) {
473                         //printf("4 parts expected, %i found\n", j);
474                         return 0;
475                 }
476                 // Parse subnet size
477                 if(Address[i] == '/') {
478                         val = 0;
479                         i ++;
480                         while('0' <= Address[i] && Address[i] <= '9') {
481                                 val *= 10;
482                                 val += Address[i] - '0';
483                                 i ++;
484                         }
485                         if(val > 32) {
486                                 printf("Notice: Subnet size >32 (%i)\n", val);
487                         }
488                         *SubnetBits = val;
489                 }
490                 if(Address[i] != '\0') {
491                         //printf("EOS != '\\0', '%c'\n", Address[i]);
492                         return 0;
493                 }
494                 return 4;
495         }
496         
497         // IPv6
498         if(*p == ':' || ('a' <= *p && *p <= 'f') || ('A' <= *p && *p <= 'F'))
499         {
500                  int    i = 0;
501                  int    j, k;
502                  int    val, split = -1, end;
503                 uint16_t        hi[8], low[8];
504                 
505                 for( j = 0; Address[i] && j < 8; j ++ )
506                 {
507                         if(Address[i] == '/')
508                                 break;
509                         
510                         if(Address[i] == ':') {
511                                 if(split != -1) {
512                                         printf("Two '::'s\n");
513                                         return 0;
514                                 }
515                                 split = j;
516                                 i ++;
517                                 continue;
518                         }
519                         
520                         val = 0;
521                         for( k = 0; Address[i] && Address[i] != ':' && Address[i] != '/'; i++, k++ )
522                         {
523                                 val *= 16;
524                                 if('0' <= Address[i] && Address[i] <= '9')
525                                         val += Address[i] - '0';
526                                 else if('A' <= Address[i] && Address[i] <= 'F')
527                                         val += Address[i] - 'A' + 10;
528                                 else if('a' <= Address[i] && Address[i] <= 'f')
529                                         val += Address[i] - 'a' + 10;
530                                 else {
531                                         printf("%c unexpected\n", Address[i]);
532                                         return 0;
533                                 }
534                         }
535                         
536                         if(val > 0xFFFF) {
537                                 printf("val (0x%x) > 0xFFFF\n", val);
538                                 return 0;
539                         }
540                         
541                         if(split == -1)
542                                 hi[j] = val;
543                         else
544                                 low[j-split] = val;
545                         
546                         if( Address[i] == ':' ) {
547                                 i ++;
548                         }
549                 }
550                 end = j;
551                 
552                 // Parse subnet size
553                 if(Address[i] == '/') {
554                         val = 0;
555                         while('0' <= Address[i] && Address[i] <= '9') {
556                                 val *= 10;
557                                 val += Address[i] - '0';
558                                 i ++;
559                         }
560                         if(val > 128) {
561                                 printf("Notice: Subnet size >128 (%i)\n", val);
562                         }
563                         *SubnetBits = val;
564                 }
565                 
566                 for( j = 0; j < split; j ++ )
567                 {
568                         //printf("%04x:", hi[j]);
569                         Dest[j*2] = hi[j]>>8;
570                         Dest[j*2+1] = hi[j]&0xFF;
571                 }
572                 for( ; j < 8 - (end - split); j++ )
573                 {
574                         //printf("0000:", hi[j]);
575                         Dest[j*2] = 0;
576                         Dest[j*2+1] = 0;
577                 }
578                 for( k = 0; j < 8; j ++, k++)
579                 {
580                         //printf("%04x:", low[k]);
581                         Dest[j*2] = low[k]>>8;
582                         Dest[j*2+1] = low[k]&0xFF;
583                 }
584                 return 6;
585         }
586         // Unknown type
587         return 0;
588 }

UCC git Repository :: git.ucc.asn.au