From 8f92cf66ba8b0bd8cc27c09075d4fa9dcb68cbd0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 May 2012 21:17:26 +0800 Subject: [PATCH] IPStack - Cleaned up userland 'ip' tool, and fixed some little bugs --- KernelLand/Modules/IPStack/adapters.c | 19 +- KernelLand/Modules/IPStack/include/adapters.h | 1 + KernelLand/Modules/IPStack/interface.c | 20 +- Makefile | 2 +- Usermode/Applications/ifconfig_src/main.c | 733 ------------------ .../{ifconfig_src => ip_src}/Makefile | 6 +- Usermode/Applications/ip_src/addr.c | 213 +++++ Usermode/Applications/ip_src/common.h | 29 + Usermode/Applications/ip_src/main.c | 224 ++++++ Usermode/Applications/ip_src/routes.c | 281 +++++++ .../{ifconfig_src => ip_src}/rules.mk | 0 11 files changed, 780 insertions(+), 748 deletions(-) delete mode 100644 Usermode/Applications/ifconfig_src/main.c rename Usermode/Applications/{ifconfig_src => ip_src}/Makefile (58%) create mode 100644 Usermode/Applications/ip_src/addr.c create mode 100644 Usermode/Applications/ip_src/common.h create mode 100644 Usermode/Applications/ip_src/main.c create mode 100644 Usermode/Applications/ip_src/routes.c rename Usermode/Applications/{ifconfig_src => ip_src}/rules.mk (100%) diff --git a/KernelLand/Modules/IPStack/adapters.c b/KernelLand/Modules/IPStack/adapters.c index f4b99beb..82894552 100644 --- a/KernelLand/Modules/IPStack/adapters.c +++ b/KernelLand/Modules/IPStack/adapters.c @@ -143,9 +143,7 @@ char *Adapter_ReadDir(tVFS_Node *Node, int Pos) tAdapter *a; int i;\ for(i=0,a=list; i < Pos && a; i ++, a = a->Next ); \ if( a ) { \ - char buf[sizeof(type)+10]; \ - sprintf(buf, type"%i", a->Index); \ - return strdup(buf); \ + return Adapter_GetName(a);\ } \ Pos -= i; \ } while(0); @@ -229,6 +227,21 @@ tAdapter *Adapter_GetByName(const char *Name) return NULL; } +char *Adapter_GetName(tAdapter *Adapter) +{ + if( Adapter == &gIP_LoopAdapter ) + { + return strdup("lo"); + } + else + { + // TODO: Support multiple adapter types + char buf[sizeof("eth")+10]; + sprintf(buf, "eth%i", Adapter->Index); + return strdup(buf); + } +} + void Adapter_SendPacket(tAdapter *Handle, tIPStackBuffer *Buffer) { if( Handle->Type == NULL ) diff --git a/KernelLand/Modules/IPStack/include/adapters.h b/KernelLand/Modules/IPStack/include/adapters.h index 768fd9e2..e0b13ffa 100644 --- a/KernelLand/Modules/IPStack/include/adapters.h +++ b/KernelLand/Modules/IPStack/include/adapters.h @@ -11,6 +11,7 @@ #include "adapters_api.h" extern tAdapter *Adapter_GetByName(const char *Name); +extern char *Adapter_GetName(tAdapter *Adapter); extern void Adapter_SendPacket(tAdapter *Handle, tIPStackBuffer *Buffer); diff --git a/KernelLand/Modules/IPStack/interface.c b/KernelLand/Modules/IPStack/interface.c index 9ff3f17d..8fe0a43e 100644 --- a/KernelLand/Modules/IPStack/interface.c +++ b/KernelLand/Modules/IPStack/interface.c @@ -440,15 +440,19 @@ int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data) * - Gets the name of the attached device */ case 8: - Log_Error("IPStack", "TODO: Reimplement interface.ioctl(get_device)"); -// if( iface->Adapter == NULL ) + if( iface->Adapter == NULL ) LEAVE_RET('i', 0); -// if( Data == NULL ) -// LEAVE_RET('i', iface->Adapter->DeviceLen); -// if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) ) -// LEAVE_RET('i', -1); -// strcpy( Data, iface->Adapter->Device ); -// LEAVE_RET('i', iface->Adapter->DeviceLen); + char *name = Adapter_GetName(iface->Adapter); + int len = strlen(name); + if( Data ) { + if( !CheckMem( Data, len+1 ) ) { + free(name); + LEAVE_RET('i', -1); + } + strcpy( Data, name ); + } + free(name); + LEAVE_RET('i', len); /* * ping diff --git a/Makefile b/Makefile index faa0ab30..54d0e167 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ USRLIBS += libimage_sif.so USRAPPS := init login CLIShell cat ls mount USRAPPS += bomb dhcpclient -USRAPPS += ifconfig ping telnet irc +USRAPPS += ip ping telnet irc USRAPPS += axwin3 ALL_DYNMODS = $(addprefix all-,$(DYNMODS)) diff --git a/Usermode/Applications/ifconfig_src/main.c b/Usermode/Applications/ifconfig_src/main.c deleted file mode 100644 index bbb8666e..00000000 --- a/Usermode/Applications/ifconfig_src/main.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Acess2 IFCONFIG command - */ -#include -#include -#include -#include -#include -#include - -// === CONSTANTS === -#define FILENAME_MAX 255 -#define IPSTACK_ROOT "/Devices/ip" -#define DEFAULT_METRIC 30 - -// TODO: Move this to a header -#define ntohs(v) (((v&0xFF)<<8)|((v>>8)&0xFF)) - -// === PROTOTYPES === -void PrintUsage(const char *ProgName); -void DumpInterfaces(void); -void DumpRoutes(void); -void DumpInterface(const char *Name); -void DumpRoute(const char *Name); - int AddInterface(const char *Device); -void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop); - int DoAutoConfig(const char *Device); - int SetAddress(int IFNum, const char *Address); - int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits); - -// === CODE === -/** - * \brief Program entrypoint - */ -int main(int argc, char *argv[]) -{ - int ret; - - // No args, dump interfaces - if(argc == 1) { - DumpInterfaces(); - return 0; - } - - // Routes - if( strcmp(argv[1], "route") == 0 ) - { - // Add new route - if( argc > 2 && strcmp(argv[2], "add") == 0 ) - { - uint8_t dest[16] = {0}; - uint8_t nextHop[16] = {0}; - int addrType, subnetBits = -1; - int nextHopType, nextHopBits=-1; - char *ifaceName = NULL; - int metric = DEFAULT_METRIC; - // Usage: - // ifconfig route add [/] [] - // ifconfig route add [/] [] - if( argc - 3 < 2 ) { - fprintf(stderr, "ERROR: '%s route add' takes at least two arguments, %i passed\n", - argv[0], argc-3); - PrintUsage(argv[0]); - return -1; - } - - if( argc - 3 > 3 ) { - fprintf(stderr, "ERROR: '%s route add' takes at most three arguments, %i passed\n", - argv[0], argc-3); - PrintUsage(argv[0]); - return -1; - } - - // Destination IP - addrType = ParseIPAddress(argv[3], dest, &subnetBits); - if( subnetBits == -1 ) { - subnetBits = Net_GetAddressSize(addrType)*8; - } - // Interface Name / Next Hop - if( (nextHopType = ParseIPAddress(argv[4], nextHop, &nextHopBits)) == 0 ) - { - // Interface name - ifaceName = argv[4]; - } - else - { - // Next Hop - // - Check if it's the same type as the network/destination - if( nextHopType != addrType ) { - fprintf(stderr, "ERROR: Address type mismatch\n"); - return -1; - } - // - Make sure there's no mask - if( nextHopBits != -1 ) { - fprintf(stderr, "Error: Next hop cannot be masked\n"); - return -1; - } - } - - // Metric - if( argc - 3 >= 3 ) - { - metric = atoi(argv[5]); - if( metric == 0 && argv[5][0] != '0' ) { - fprintf(stderr, "ERROR: Metric should be a number\n"); - return -1; - } - } - - // Make the route! - AddRoute(ifaceName, addrType, dest, subnetBits, metric, nextHop); - - return 0; - } - // Delete a route - else if( argc > 2 && strcmp(argv[2], "del") == 0 ) - { - // Usage: - // ifconfig route del - // ifconfig route del [/] - } - else - { - // List routes - DumpRoutes(); - } - return 0; - } - // Add a new interface - else if( strcmp(argv[1], "add") == 0 ) - { - if( argc < 4 ) { - fprintf(stderr, "ERROR: '%s add' requires two arguments, %i passed\n", argv[0], argc-2); - PrintUsage(argv[0]); - return -1; - } - ret = AddInterface( argv[2] ); - if(ret < 0) return ret; - ret = SetAddress( ret, argv[3] ); - return ret; - } - // Delete an interface - else if( strcmp(argv[1], "del") == 0 ) - { - if( argc < 3 ) { - fprintf(stderr, "ERROR: '%s del' requires an argument\n", argv[0]); - PrintUsage(argv[0]); - return -1; - } - // TODO: - } - // Autoconfigure an interface - // NOTE: Debugging hack (see the function for more details) - else if( strcmp(argv[1], "autoconf") == 0 ) - { - DoAutoConfig(argv[2]); - return 0; - } - else if( strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0 ) - { - PrintUsage(argv[0]); - return 0; - } - - // Dump a named interface - DumpInterface(argv[1]); - - return 0; -} - -/** - * \brief Print usage instructions - */ -void PrintUsage(const char *ProgName) -{ - fprintf(stderr, "Usage:\n"); - fprintf(stderr, " %s add /\n", ProgName); - fprintf(stderr, " Add a new interface listening on with the specified\n"); - fprintf(stderr, " address.\n"); - fprintf(stderr, " %s del \n", ProgName); - fprintf(stderr, " Delete an interface\n"); - fprintf(stderr, " %s []\n", ProgName); - fprintf(stderr, " Print the current interfaces (or only if passed)\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " %s route\n", ProgName); - fprintf(stderr, " Print the routing tables\n"); - fprintf(stderr, " %s route add [/] [ OR ] []\n", ProgName); - fprintf(stderr, " Add a new route\n"); - fprintf(stderr, " %s route del [/]\n", ProgName); - fprintf(stderr, " %s route del \n", ProgName); - fprintf(stderr, " Add a new route\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "A note on Acess's IP Stack:\n"); - fprintf(stderr, " Each interface corresponds to only one IP address (either IPv4\n"); - fprintf(stderr, " or IPv6). A network device can have multiple interfaces bound\n"); - fprintf(stderr, " to it, allowing multiple addresses for one network connection\n"); - fprintf(stderr, "\n"); -} - -/** - * \brief Dump all interfaces - */ -void DumpInterfaces(void) -{ - int dp; - char filename[FILENAME_MAX+1]; - - dp = open(IPSTACK_ROOT, OPENFLAG_READ); - - while( readdir(dp, filename) ) - { - if(filename[0] == '.') continue; - DumpInterface(filename); - } - - close(dp); -} - -/** - * \brief Dump all interfaces - */ -void DumpRoutes(void) -{ - int dp; - char filename[FILENAME_MAX+1]; - - dp = open(IPSTACK_ROOT"/routes", OPENFLAG_READ); - - printf("Type\tNetwork \tGateway \tMetric\tIFace\n"); - - while( readdir(dp, filename) ) - { - if(filename[0] == '.') continue; - DumpRoute(filename); - } - - close(dp); -} - -/** - * \brief Dump an interface - */ -void DumpInterface(const char *Name) -{ - int fd; - int type; - char path[sizeof(IPSTACK_ROOT)+1+FILENAME_MAX+1] = IPSTACK_ROOT"/"; - - strcat(path, Name); - - fd = open(path, OPENFLAG_READ); - if(fd == -1) { - fprintf(stderr, "Bad interface name '%s' (%s does not exist)\t", Name, path); - return ; - } - - type = ioctl(fd, 4, NULL); - - // Ignore -1 values - if( type == -1 ) { - return ; - } - - printf("%s:\t", Name); - { - int call_num = ioctl(fd, 3, "get_device"); - int len = ioctl(fd, call_num, NULL); - char *buf = malloc(len+1); - ioctl(fd, call_num, buf); - printf("'%s'\n", buf); - free(buf); - } - printf("\t"); - // Get the address type - switch(type) - { - case 0: // Disabled/Unset - printf("DISABLED\n"); - break; - case 4: // IPv4 - { - uint8_t ip[4]; - int subnet; - printf("IPv4\t"); - ioctl(fd, 5, ip); // Get IP Address - subnet = ioctl(fd, 7, NULL); // Get Subnet Bits - printf("%i.%i.%i.%i/%i\n", ip[0], ip[1], ip[2], ip[3], subnet); - } - break; - case 6: // IPv6 - { - uint16_t ip[8]; - int subnet; - printf("IPv6\t"); - ioctl(fd, 5, ip); // Get IP Address - subnet = ioctl(fd, 7, NULL); // Get Subnet Bits - printf("%x:%x:%x:%x:%x:%x:%x:%x/%i\n", - ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]), - ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]), - subnet); - } - break; - default: // Unknow - printf("UNKNOWN (%i)\n", type); - break; - } - - close(fd); -} - - -/** - * \brief Dump a route - */ -void DumpRoute(const char *Name) -{ - int fd; - int type; - char path[sizeof(IPSTACK_ROOT)+8+FILENAME_MAX+1] = IPSTACK_ROOT"/routes/"; - - strcat(path, Name); - - fd = open(path, OPENFLAG_READ); - if(fd == -1) { - printf("%s:\tUnable to open ('%s')\n", Name, path); - return ; - } - - int ofs = 2; - type = atoi(Name); - - int i; - int len = Net_GetAddressSize(type); - uint8_t net[len], gw[len]; - int subnet, metric; - for( i = 0; i < len; i ++ ) { - char tmp[5] = "0x00"; - tmp[2] = Name[ofs++]; - tmp[3] = Name[ofs++]; - net[i] = atoi(tmp); - } - ofs ++; - subnet = atoi(Name+ofs); - ofs ++; - metric = atoi(Name+ofs); - ioctl(fd, ioctl(fd, 3, "get_nexthop"), gw); // Get Gateway/NextHop - - // Get the address type - switch(type) - { - case 0: // Disabled/Unset - printf("DISABLED\n"); - break; - case 4: // IPv4 - printf("IPv4\t"); - break; - case 6: // IPv6 - printf("IPv6\t"); - break; - default: // Unknow - printf("UNKNOWN (%i)\n", type); - break; - } - printf("%s/%i\t", Net_PrintAddress(type, net), subnet); - printf("%s \t", Net_PrintAddress(type, gw)); - printf("%i\t", metric); - - // Interface - { - int call_num = ioctl(fd, 3, "get_interface"); - int len = ioctl(fd, call_num, NULL); - char *buf = malloc(len+1); - ioctl(fd, call_num, buf); - printf("'%s'\t", buf); - free(buf); - } - - printf("\n"); - - close(fd); -} - -/** - * \brief Create a new interface using the passed device - * \param Device Network device to bind to - */ -int AddInterface(const char *Device) -{ - int dp, ret; - - dp = open(IPSTACK_ROOT, OPENFLAG_READ); - ret = ioctl(dp, 4, (void*)Device); - close(dp); - - if( ret < 0 ) { - fprintf(stderr, "Unable to add '%s' as a network interface\n", Device); - return -1; - } - - printf("-- Added '"IPSTACK_ROOT"/%i' using device %s\n", ret, Device); - - return ret; -} - -void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop) -{ - int fd; - int num; - char *ifaceToFree = NULL; - - // Get interface name - if( !Interface ) - { - if( !NextHop ) { - fprintf(stderr, - "BUG: AddRoute(Interface=NULL,...,NextHop=NULL)\n" - "Only one should be NULL\n" - ); - return ; - } - - // Query for the interface name - Interface = ifaceToFree = Net_GetInterface(AddressType, NextHop); - } - // Check address type (if the interface was passed) - // - If we got the interface name, then it should be correct - else - { - char ifacePath[sizeof(IPSTACK_ROOT"/")+strlen(Interface)+1]; - - // Open interface - strcpy(ifacePath, IPSTACK_ROOT"/"); - strcat(ifacePath, Interface); - fd = open(ifacePath, 0); - if( fd == -1 ) { - fprintf(stderr, "Error: Interface '%s' does not exist\n", Interface); - return ; - } - // Get and check type - num = ioctl(fd, ioctl(fd, 3, "getset_type"), NULL); - if( num != AddressType ) { - fprintf(stderr, "Error: Passed type does not match interface type (%i != %i)\n", - AddressType, num); - return ; - } - - close(fd); - } - - // Create route - int addrsize = Net_GetAddressSize(AddressType); - int len = snprintf(NULL, 0, "/Devices/ip/routes/%i::%i:%i", AddressType, MaskBits, Metric) + addrsize*2; - char path[len+1]; - { - int i, ofs; - ofs = sprintf(path, "/Devices/ip/routes/%i:", AddressType); - for( i = 0; i < addrsize; i ++ ) - sprintf(path+ofs+i*2, "%02x", ((uint8_t*)Dest)[i]); - ofs += addrsize*2; - sprintf(path+ofs, ":%i:%i", MaskBits, Metric); - } - - fd = open(path, 0); - if( fd != -1 ) { - close(fd); - fprintf(stderr, "Unable to create route '%s', already exists\n", path); - return ; - } - fd = open(path, OPENFLAG_CREATE, 0); - if( fd == -1 ) { - fprintf(stderr, "Unable to create '%s'\n", path); - return ; - } - - if( NextHop ) - ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop); - ioctl(fd, ioctl(fd, 3, "set_interface"), (void*)Interface); - - close(fd); - - // Check if the interface name was allocated by us - if( ifaceToFree ) - free(ifaceToFree); -} - -/** - * \note Debugging HACK! - * \brief Autoconfigure the specified device to 10.0.2.55/24 using - * 10.0.2.2 as the gateway. - */ -int DoAutoConfig(const char *Device) -{ - int tmp, fd; - char path[sizeof(IPSTACK_ROOT)+1+4+1]; // /0000 - uint8_t addr[4] = {10,0,2,55}; - uint8_t gw[4] = {10,0,2,2}; - int subnet = 24; - - tmp = AddInterface(Device); - if( tmp < 0 ) return tmp; - - sprintf(path, IPSTACK_ROOT"/%i", tmp); - - fd = open(path, OPENFLAG_READ); - if( fd == -1 ) { - fprintf(stderr, "Unable to open '%s'\n", path); - return -1; - } - - tmp = 4; // IPv4 - tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp); - if( tmp != 4 ) { - fprintf(stderr, "Error in setting address type (got %i, expected 4)\n", tmp); - return -1; - } - // Set Address - ioctl(fd, ioctl(fd, 3, "set_address"), addr); - // Set Subnet - ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet); - - // Set routes - { - uint8_t net[4] = {0,0,0,0}; - AddRoute(path + sizeof(IPSTACK_ROOT), 4, addr, subnet, DEFAULT_METRIC, net); // This interface - AddRoute(path + sizeof(IPSTACK_ROOT), 4, net, 0, DEFAULT_METRIC, gw); // Gateway - } - - close(fd); - - printf("Set address to %i.%i.%i.%i/%i (GW: %i.%i.%i.%i)\n", - addr[0], addr[1], addr[2], addr[3], - subnet, - gw[0], gw[1], gw[2], gw[3]); - - return 0; -} - -/** - * \brief Set the address on an interface from a textual IP address - */ -int SetAddress(int IFNum, const char *Address) -{ - uint8_t addr[16]; - int type; - char path[sizeof(IPSTACK_ROOT)+1+5+1]; // ip000 - int tmp, fd, subnet; - - // Parse IP Address - type = ParseIPAddress(Address, addr, &subnet); - if(type == 0) { - fprintf(stderr, "'%s' cannot be parsed as an IP address\n", Address); - return -1; - } - - // Open file - sprintf(path, IPSTACK_ROOT"/%i", IFNum); - fd = open(path, OPENFLAG_READ); - if( fd == -1 ) { - fprintf(stderr, "Unable to open '%s'\n", path); - return -1; - } - - tmp = type; - tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp); - if( tmp != type ) { - fprintf(stderr, "Error in setting address type (got %i, expected %i)\n", tmp, type); - close(fd); - return -1; - } - // Set Address - ioctl(fd, ioctl(fd, 3, "set_address"), addr); - - // Set Subnet - ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet); - - close(fd); - - // Dump! - //DumpInterface( path+sizeof(IPSTACK_ROOT)+1 ); - - return 0; -} - -/** - * \brief Parse an IP Address - * \return 0 for unknown, 4 for IPv4 and 6 for IPv6 - */ -int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits) -{ - const char *p = Address; - - // Check first block - while(*p && *p >= '0' && *p <= '9') p ++; - - // IPv4? - if(*p == '.') - { - int i = 0, j; - int val; - - for( j = 0; Address[i] && j < 4; j ++ ) - { - val = 0; - for( ; '0' <= Address[i] && Address[i] <= '9'; i++ ) - { - val = val*10 + Address[i] - '0'; - } - if(val > 255) { - //printf("val > 255 (%i)\n", val); - return 0; - } - Dest[j] = val; - - if(Address[i] == '.') - i ++; - } - if( j != 4 ) { - //printf("4 parts expected, %i found\n", j); - return 0; - } - // Parse subnet size - if(Address[i] == '/') { - val = 0; - i ++; - while('0' <= Address[i] && Address[i] <= '9') { - val *= 10; - val += Address[i] - '0'; - i ++; - } - if(val > 32) { - printf("Notice: Subnet size >32 (%i)\n", val); - } - if(SubnetBits) *SubnetBits = val; - } - if(Address[i] != '\0') { - //printf("EOS != '\\0', '%c'\n", Address[i]); - return 0; - } - return 4; - } - - // IPv6 - if(*p == ':' || ('a' <= *p && *p <= 'f') || ('A' <= *p && *p <= 'F')) - { - int i = 0; - int j, k; - int val, split = -1, end; - uint16_t hi[8], low[8]; - - for( j = 0; Address[i] && j < 8; j ++ ) - { - if(Address[i] == '/') - break; - - if(Address[i] == ':') { - if(split != -1) { - printf("Two '::'s\n"); - return 0; - } - split = j; - i ++; - continue; - } - - val = 0; - for( k = 0; Address[i] && Address[i] != ':' && Address[i] != '/'; i++, k++ ) - { - val *= 16; - if('0' <= Address[i] && Address[i] <= '9') - val += Address[i] - '0'; - else if('A' <= Address[i] && Address[i] <= 'F') - val += Address[i] - 'A' + 10; - else if('a' <= Address[i] && Address[i] <= 'f') - val += Address[i] - 'a' + 10; - else { - printf("%c unexpected\n", Address[i]); - return 0; - } - } - - if(val > 0xFFFF) { - printf("val (0x%x) > 0xFFFF\n", val); - return 0; - } - - if(split == -1) - hi[j] = val; - else - low[j-split] = val; - - if( Address[i] == ':' ) { - i ++; - } - } - end = j; - - // Parse subnet size - if(Address[i] == '/') { - val = 0; - while('0' <= Address[i] && Address[i] <= '9') { - val *= 10; - val += Address[i] - '0'; - i ++; - } - if(val > 128) { - printf("Notice: Subnet size >128 (%i)\n", val); - } - if(SubnetBits) *SubnetBits = val; - } - - for( j = 0; j < split; j ++ ) - { - //printf("%04x:", hi[j]); - Dest[j*2] = hi[j]>>8; - Dest[j*2+1] = hi[j]&0xFF; - } - for( ; j < 8 - (end - split); j++ ) - { - //printf("0000:", hi[j]); - Dest[j*2] = 0; - Dest[j*2+1] = 0; - } - for( k = 0; j < 8; j ++, k++) - { - //printf("%04x:", low[k]); - Dest[j*2] = low[k]>>8; - Dest[j*2+1] = low[k]&0xFF; - } - return 6; - } - // Unknown type - return 0; -} diff --git a/Usermode/Applications/ifconfig_src/Makefile b/Usermode/Applications/ip_src/Makefile similarity index 58% rename from Usermode/Applications/ifconfig_src/Makefile rename to Usermode/Applications/ip_src/Makefile index e914e2b6..1c976b50 100644 --- a/Usermode/Applications/ifconfig_src/Makefile +++ b/Usermode/Applications/ip_src/Makefile @@ -1,11 +1,11 @@ -# Project: ifconfig +# Project: ip -include ../Makefile.cfg LDFLAGS += -lnet -OBJ = main.o -BIN = ifconfig +OBJ = main.o addr.o routes.o +BIN = ip -include ../Makefile.tpl diff --git a/Usermode/Applications/ip_src/addr.c b/Usermode/Applications/ip_src/addr.c new file mode 100644 index 00000000..579aa477 --- /dev/null +++ b/Usermode/Applications/ip_src/addr.c @@ -0,0 +1,213 @@ +/* + * Acess2 ip command + * - By John Hodge (thePowersGang) + * + * addr.c + * - `ip addr` sub command + */ +#include "common.h" + +// === PROTOTYPES === + int Addr_main(int argc, char *argv[]); + int AddInterface(const char *Device); + int SetAddress(int IFNum, const char *Address); +void DumpInterfaces(void); +void DumpInterface(const char *Name); +void DumpRoute(const char *Name); + +// === CODE === +int Addr_main(int argc, char *argv[]) +{ + int ret; + if( argc <= 1 ) + { + // No action + DumpInterfaces(); + } + else if( strcmp(argv[1], "add") == 0 ) + { + if( argc - 2 < 2 ) { + fprintf(stderr, "ERROR: '%s add' requires two arguments, %i passed\n", argv[0], argc-2); + PrintUsage(argv[0]); + return -1; + } + ret = AddInterface( argv[2] ); + if(ret < 0) return ret; + ret = SetAddress( ret, argv[3] ); + return ret; + } + // Delete an interface + else if( strcmp(argv[1], "del") == 0 ) + { + if( argc - 2 < 1 ) { + fprintf(stderr, "ERROR: '%s del' requires an argument\n", argv[0]); + PrintUsage(argv[0]); + return -1; + } + } + else + { + // Show named iface? + DumpInterface(argv[1]); + } + return 0; +} + +/** + * \brief Create a new interface using the passed device + * \param Device Network device to bind to + */ +int AddInterface(const char *Device) +{ + int dp, ret; + + dp = open(IPSTACK_ROOT, OPENFLAG_READ); + ret = ioctl(dp, 4, (void*)Device); + close(dp); + + if( ret < 0 ) { + fprintf(stderr, "Unable to add '%s' as a network interface\n", Device); + return -1; + } + + printf("-- Added '"IPSTACK_ROOT"/%i' using device %s\n", ret, Device); + + return ret; +} + +/** + * \brief Set the address on an interface from a textual IP address + */ +int SetAddress(int IFNum, const char *Address) +{ + uint8_t addr[16]; + int type; + char path[sizeof(IPSTACK_ROOT)+1+5+1]; // ip000 + int tmp, fd, subnet; + + // Parse IP Address + type = ParseIPAddress(Address, addr, &subnet); + if(type == 0) { + fprintf(stderr, "'%s' cannot be parsed as an IP address\n", Address); + return -1; + } + + // Open file + sprintf(path, IPSTACK_ROOT"/%i", IFNum); + fd = open(path, OPENFLAG_READ); + if( fd == -1 ) { + fprintf(stderr, "Unable to open '%s'\n", path); + return -1; + } + + tmp = type; + tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp); + if( tmp != type ) { + fprintf(stderr, "Error in setting address type (got %i, expected %i)\n", tmp, type); + close(fd); + return -1; + } + // Set Address + ioctl(fd, ioctl(fd, 3, "set_address"), addr); + + // Set Subnet + ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet); + + close(fd); + + // Dump! + //DumpInterface( path+sizeof(IPSTACK_ROOT)+1 ); + + return 0; +} + +/** + * \brief Dump all interfaces + */ +void DumpInterfaces(void) +{ + int dp; + char filename[FILENAME_MAX+1]; + + dp = open(IPSTACK_ROOT, OPENFLAG_READ); + + while( readdir(dp, filename) ) + { + if(filename[0] == '.') continue; + DumpInterface(filename); + } + + close(dp); +} + +/** + * \brief Dump an interface + */ +void DumpInterface(const char *Name) +{ + int fd; + int type; + char path[sizeof(IPSTACK_ROOT)+1+FILENAME_MAX+1] = IPSTACK_ROOT"/"; + + strcat(path, Name); + + fd = open(path, OPENFLAG_READ); + if(fd == -1) { + fprintf(stderr, "Bad interface name '%s' (%s does not exist)\t", Name, path); + return ; + } + + type = ioctl(fd, 4, NULL); + + // Ignore -1 values + if( type == -1 ) { + return ; + } + + printf("%s:\t", Name); + { + int call_num = ioctl(fd, 3, "get_device"); + int len = ioctl(fd, call_num, NULL); + char *buf = malloc(len+1); + ioctl(fd, call_num, buf); + printf("'%s'\n", buf); + free(buf); + } + printf("\t"); + // Get the address type + switch(type) + { + case 0: // Disabled/Unset + printf("DISABLED\n"); + break; + case 4: // IPv4 + { + uint8_t ip[4]; + int subnet; + printf("IPv4\t"); + ioctl(fd, 5, ip); // Get IP Address + subnet = ioctl(fd, 7, NULL); // Get Subnet Bits + printf("%i.%i.%i.%i/%i\n", ip[0], ip[1], ip[2], ip[3], subnet); + } + break; + case 6: // IPv6 + { + uint16_t ip[8]; + int subnet; + printf("IPv6\t"); + ioctl(fd, 5, ip); // Get IP Address + subnet = ioctl(fd, 7, NULL); // Get Subnet Bits + printf("%x:%x:%x:%x:%x:%x:%x:%x/%i\n", + ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]), + ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]), + subnet); + } + break; + default: // Unknow + printf("UNKNOWN (%i)\n", type); + break; + } + + close(fd); +} + diff --git a/Usermode/Applications/ip_src/common.h b/Usermode/Applications/ip_src/common.h new file mode 100644 index 00000000..f4aa373a --- /dev/null +++ b/Usermode/Applications/ip_src/common.h @@ -0,0 +1,29 @@ +/* + * Acess2 ip command + * - By John Hodge (thePowersGang) + * + * common.h + * - Shared header + */ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include +#include +#include +#include +#include +#include + +#define FILENAME_MAX 255 +#define IPSTACK_ROOT "/Devices/ip" + +#define ntohs(v) (((v&0xFF)<<8)|((v>>8)&0xFF)) + +extern void PrintUsage(const char *ProgName); +extern int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits); +extern int Addr_main(int argc, char *argv[]); +extern int Routes_main(int argc, char *argv[]); + +#endif + diff --git a/Usermode/Applications/ip_src/main.c b/Usermode/Applications/ip_src/main.c new file mode 100644 index 00000000..580fb4ec --- /dev/null +++ b/Usermode/Applications/ip_src/main.c @@ -0,0 +1,224 @@ +/* + * Acess2 ip command + * - By John Hodge (thePowersGang) + */ +#include "common.h" + +// === CONSTANTS === + +// === PROTOTYPES === +void PrintUsage(const char *ProgName); + int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits); + +// === CODE === +/** + * \brief Program entrypoint + */ +int main(int argc, char *argv[]) +{ + // No args, dump interfaces + if(argc == 1) { +// DumpInterfaces(); + return 0; + } + + // Routes + if( strcmp(argv[1], "route") == 0 ) + { + Routes_main(argc-1, argv+1); + return 0; + } + else if( strcmp(argv[1], "addr") == 0 ) + { + Addr_main(argc-1, argv+1); + return 0; + } + else if( strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0 ) + { + PrintUsage(argv[0]); + return 0; + } + + return 0; +} + +/** + * \brief Print usage instructions + */ +void PrintUsage(const char *ProgName) +{ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s addr add /\n", ProgName); + fprintf(stderr, " Add a new interface listening on with the specified\n"); + fprintf(stderr, " address.\n"); + fprintf(stderr, " %s addr del \n", ProgName); + fprintf(stderr, " Delete an interface\n"); + fprintf(stderr, " %s addr []\n", ProgName); + fprintf(stderr, " Print the current interfaces (or only if passed)\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " %s route\n", ProgName); + fprintf(stderr, " Print the routing tables\n"); + fprintf(stderr, " %s route add [/] [ OR ] []\n", ProgName); + fprintf(stderr, " Add a new route\n"); + fprintf(stderr, " %s route del [/]\n", ProgName); + fprintf(stderr, " %s route del \n", ProgName); + fprintf(stderr, " Add a new route\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "A note on Acess's IP Stack:\n"); + fprintf(stderr, " Each interface corresponds to only one IP address (either IPv4\n"); + fprintf(stderr, " or IPv6). A network device can have multiple interfaces bound\n"); + fprintf(stderr, " to it, allowing multiple addresses for one network connection\n"); + fprintf(stderr, "\n"); +} + + +/** + * \brief Parse an IP Address + * \return 0 for unknown, 4 for IPv4 and 6 for IPv6 + */ +int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits) +{ + const char *p = Address; + + // Check first block + while(*p && *p >= '0' && *p <= '9') p ++; + + // IPv4? + if(*p == '.') + { + int i = 0, j; + int val; + + for( j = 0; Address[i] && j < 4; j ++ ) + { + val = 0; + for( ; '0' <= Address[i] && Address[i] <= '9'; i++ ) + { + val = val*10 + Address[i] - '0'; + } + if(val > 255) { + //printf("val > 255 (%i)\n", val); + return 0; + } + Dest[j] = val; + + if(Address[i] == '.') + i ++; + } + if( j != 4 ) { + //printf("4 parts expected, %i found\n", j); + return 0; + } + // Parse subnet size + if(Address[i] == '/') { + val = 0; + i ++; + while('0' <= Address[i] && Address[i] <= '9') { + val *= 10; + val += Address[i] - '0'; + i ++; + } + if(val > 32) { + printf("Notice: Subnet size >32 (%i)\n", val); + } + if(SubnetBits) *SubnetBits = val; + } + if(Address[i] != '\0') { + //printf("EOS != '\\0', '%c'\n", Address[i]); + return 0; + } + return 4; + } + + // IPv6 + if(*p == ':' || ('a' <= *p && *p <= 'f') || ('A' <= *p && *p <= 'F')) + { + int i = 0; + int j, k; + int val, split = -1, end; + uint16_t hi[8], low[8]; + + for( j = 0; Address[i] && j < 8; j ++ ) + { + if(Address[i] == '/') + break; + + if(Address[i] == ':') { + if(split != -1) { + printf("Two '::'s\n"); + return 0; + } + split = j; + i ++; + continue; + } + + val = 0; + for( k = 0; Address[i] && Address[i] != ':' && Address[i] != '/'; i++, k++ ) + { + val *= 16; + if('0' <= Address[i] && Address[i] <= '9') + val += Address[i] - '0'; + else if('A' <= Address[i] && Address[i] <= 'F') + val += Address[i] - 'A' + 10; + else if('a' <= Address[i] && Address[i] <= 'f') + val += Address[i] - 'a' + 10; + else { + printf("%c unexpected\n", Address[i]); + return 0; + } + } + + if(val > 0xFFFF) { + printf("val (0x%x) > 0xFFFF\n", val); + return 0; + } + + if(split == -1) + hi[j] = val; + else + low[j-split] = val; + + if( Address[i] == ':' ) { + i ++; + } + } + end = j; + + // Parse subnet size + if(Address[i] == '/') { + val = 0; + while('0' <= Address[i] && Address[i] <= '9') { + val *= 10; + val += Address[i] - '0'; + i ++; + } + if(val > 128) { + printf("Notice: Subnet size >128 (%i)\n", val); + } + if(SubnetBits) *SubnetBits = val; + } + + for( j = 0; j < split; j ++ ) + { + //printf("%04x:", hi[j]); + Dest[j*2] = hi[j]>>8; + Dest[j*2+1] = hi[j]&0xFF; + } + for( ; j < 8 - (end - split); j++ ) + { + //printf("0000:", hi[j]); + Dest[j*2] = 0; + Dest[j*2+1] = 0; + } + for( k = 0; j < 8; j ++, k++) + { + //printf("%04x:", low[k]); + Dest[j*2] = low[k]>>8; + Dest[j*2+1] = low[k]&0xFF; + } + return 6; + } + // Unknown type + return 0; +} diff --git a/Usermode/Applications/ip_src/routes.c b/Usermode/Applications/ip_src/routes.c new file mode 100644 index 00000000..1d60fbc6 --- /dev/null +++ b/Usermode/Applications/ip_src/routes.c @@ -0,0 +1,281 @@ +/* + * Acess2 ip command + * - By John Hodge (thePowersGang) + * + * routes.c + * - `ip route` sub-command + */ +#include "common.h" + +#define DEFAULT_METRIC 30 + +// === PROTOTYPES === + int Routes_main(int argc, char *argv[]); +void DumpRoutes(void); +void DumpRoute(const char *Name); +void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop); + +// === CODE === +int Routes_main(int argc, char *argv[]) +{ + if( argc <= 1 ) + { + // Show routes + DumpRoutes(); + } + // Add new route + else if( strcmp(argv[1], "add") == 0 ) + { + uint8_t dest[16] = {0}; + uint8_t nextHop[16] = {0}; + int addrType, subnetBits = -1; + int nextHopType, nextHopBits=-1; + char *ifaceName = NULL; + int metric = DEFAULT_METRIC; + // Usage: + // ifconfig route add [/] [] + // ifconfig route add [/] [] + if( argc - 2 < 2 ) { + fprintf(stderr, "ERROR: '%s route add' takes at least two arguments, %i passed\n", + argv[0], argc-3); + PrintUsage(argv[0]); + return -1; + } + + if( argc - 2 > 3 ) { + fprintf(stderr, "ERROR: '%s route add' takes at most three arguments, %i passed\n", + argv[0], argc-3); + PrintUsage(argv[0]); + return -1; + } + + // Destination IP + addrType = ParseIPAddress(argv[3], dest, &subnetBits); + if( subnetBits == -1 ) { + subnetBits = Net_GetAddressSize(addrType)*8; + } + // Interface Name / Next Hop + if( (nextHopType = ParseIPAddress(argv[4], nextHop, &nextHopBits)) == 0 ) + { + // Interface name + ifaceName = argv[4]; + } + else + { + // Next Hop + // - Check if it's the same type as the network/destination + if( nextHopType != addrType ) { + fprintf(stderr, "ERROR: Address type mismatch\n"); + return -1; + } + // - Make sure there's no mask + if( nextHopBits != -1 ) { + fprintf(stderr, "Error: Next hop cannot be masked\n"); + return -1; + } + } + + // Metric + if( argc - 3 >= 3 ) + { + metric = atoi(argv[5]); + if( metric == 0 && argv[5][0] != '0' ) { + fprintf(stderr, "ERROR: Metric should be a number\n"); + return -1; + } + } + + // Make the route! + AddRoute(ifaceName, addrType, dest, subnetBits, metric, nextHop); + + return 0; + } + // Delete a route + else if( strcmp(argv[2], "del") == 0 ) + { + // Usage: + // ifconfig route del + // ifconfig route del [/] + } + else + { + // List routes + DumpRoutes(); + } + + return 0; +} + +/** + * \brief Dump all interfaces + */ +void DumpRoutes(void) +{ + int dp; + char filename[FILENAME_MAX+1]; + + dp = open(IPSTACK_ROOT"/routes", OPENFLAG_READ); + + printf("Type\tNetwork \tGateway \tMetric\tIFace\n"); + + while( readdir(dp, filename) ) + { + if(filename[0] == '.') continue; + DumpRoute(filename); + } + + close(dp); +} + +/** + * \brief Dump a route + */ +void DumpRoute(const char *Name) +{ + int fd; + int type; + char path[sizeof(IPSTACK_ROOT)+8+FILENAME_MAX+1] = IPSTACK_ROOT"/routes/"; + + strcat(path, Name); + + fd = open(path, OPENFLAG_READ); + if(fd == -1) { + printf("%s:\tUnable to open ('%s')\n", Name, path); + return ; + } + + int ofs = 2; + type = atoi(Name); + + int i; + int len = Net_GetAddressSize(type); + uint8_t net[len], gw[len]; + int subnet, metric; + for( i = 0; i < len; i ++ ) { + char tmp[5] = "0x00"; + tmp[2] = Name[ofs++]; + tmp[3] = Name[ofs++]; + net[i] = atoi(tmp); + } + ofs ++; + subnet = atoi(Name+ofs); + ofs ++; + metric = atoi(Name+ofs); + ioctl(fd, ioctl(fd, 3, "get_nexthop"), gw); // Get Gateway/NextHop + + // Get the address type + switch(type) + { + case 0: // Disabled/Unset + printf("DISABLED\n"); + break; + case 4: // IPv4 + printf("IPv4\t"); + break; + case 6: // IPv6 + printf("IPv6\t"); + break; + default: // Unknow + printf("UNKNOWN (%i)\n", type); + break; + } + printf("%s/%i\t", Net_PrintAddress(type, net), subnet); + printf("%s \t", Net_PrintAddress(type, gw)); + printf("%i\t", metric); + + // Interface + { + int call_num = ioctl(fd, 3, "get_interface"); + int len = ioctl(fd, call_num, NULL); + char *buf = malloc(len+1); + ioctl(fd, call_num, buf); + printf("'%s'\t", buf); + free(buf); + } + + printf("\n"); + + close(fd); +} + +void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop) +{ + int fd; + int num; + char *ifaceToFree = NULL; + + // Get interface name + if( !Interface ) + { + if( !NextHop ) { + fprintf(stderr, + "BUG: AddRoute(Interface=NULL,...,NextHop=NULL)\n" + "Only one should be NULL\n" + ); + return ; + } + + // Query for the interface name + Interface = ifaceToFree = Net_GetInterface(AddressType, NextHop); + } + // Check address type (if the interface was passed) + // - If we got the interface name, then it should be correct + else + { + char ifacePath[sizeof(IPSTACK_ROOT"/")+strlen(Interface)+1]; + + // Open interface + strcpy(ifacePath, IPSTACK_ROOT"/"); + strcat(ifacePath, Interface); + fd = open(ifacePath, 0); + if( fd == -1 ) { + fprintf(stderr, "Error: Interface '%s' does not exist\n", Interface); + return ; + } + // Get and check type + num = ioctl(fd, ioctl(fd, 3, "getset_type"), NULL); + if( num != AddressType ) { + fprintf(stderr, "Error: Passed type does not match interface type (%i != %i)\n", + AddressType, num); + return ; + } + + close(fd); + } + + // Create route + int addrsize = Net_GetAddressSize(AddressType); + int len = snprintf(NULL, 0, "/Devices/ip/routes/%i::%i:%i", AddressType, MaskBits, Metric) + addrsize*2; + char path[len+1]; + { + int i, ofs; + ofs = sprintf(path, "/Devices/ip/routes/%i:", AddressType); + for( i = 0; i < addrsize; i ++ ) + sprintf(path+ofs+i*2, "%02x", ((uint8_t*)Dest)[i]); + ofs += addrsize*2; + sprintf(path+ofs, ":%i:%i", MaskBits, Metric); + } + + fd = open(path, 0); + if( fd != -1 ) { + close(fd); + fprintf(stderr, "Unable to create route '%s', already exists\n", path); + return ; + } + fd = open(path, OPENFLAG_CREATE, 0); + if( fd == -1 ) { + fprintf(stderr, "Unable to create '%s'\n", path); + return ; + } + + if( NextHop ) + ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop); + ioctl(fd, ioctl(fd, 3, "set_interface"), (void*)Interface); + + close(fd); + + // Check if the interface name was allocated by us + if( ifaceToFree ) + free(ifaceToFree); +} + diff --git a/Usermode/Applications/ifconfig_src/rules.mk b/Usermode/Applications/ip_src/rules.mk similarity index 100% rename from Usermode/Applications/ifconfig_src/rules.mk rename to Usermode/Applications/ip_src/rules.mk -- 2.20.1