From 341d51ca40a4a26ed89914feaacc940c64b22197 Mon Sep 17 00:00:00 2001 From: "John Hodge (sonata)" Date: Mon, 16 Feb 2015 09:18:54 +0800 Subject: [PATCH 01/16] Usermode/(libnet,libpsocket) - Call new DNS code from getaddrinfo --- Usermode/Libraries/libnet.so_src/hostnames.c | 83 ++++++++---- .../Libraries/libnet.so_src/include/dns.h | 2 +- .../Libraries/libnet.so_src/include_exp/net.h | 10 ++ .../Libraries/libpsocket.so_src/getaddrinfo.c | 126 ++++++++++++++---- 4 files changed, 173 insertions(+), 48 deletions(-) diff --git a/Usermode/Libraries/libnet.so_src/hostnames.c b/Usermode/Libraries/libnet.so_src/hostnames.c index 203f4aa4..88093de3 100644 --- a/Usermode/Libraries/libnet.so_src/hostnames.c +++ b/Usermode/Libraries/libnet.so_src/hostnames.c @@ -24,16 +24,23 @@ struct sHostEntry char *Names[]; }; -struct sDNSCallbackInfo +struct sLookupAnyInfo { - int expected_size; + int expected_type; void *dest_ptr; + bool have_result; +}; +struct sDNSCallbackInfo +{ + void *cb_info; + tNet_LookupAddrs_Callback *callback; enum eTypes desired_type; enum eClass desired_class; - bool have_result; + bool got_value; }; // === PROTOTYPES === + int int_lookupany_callback(void *info_v, int AddrType, const void *Addr); void int_DNS_callback(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); // === GLOBALS === @@ -44,6 +51,28 @@ struct sHostEntry *gaHostEntries; // === CODE === int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr) +{ + struct sLookupAnyInfo cb_info = { + .expected_type = AddrType, + .dest_ptr = Addr, + .have_result = false, + }; + return Net_Lookup_Addrs(Name, &cb_info, int_lookupany_callback); +} +int int_lookupany_callback(void *info_v, int AddrType, const void *Addr) +{ + struct sLookupAnyInfo *info = info_v; + if( AddrType == info->expected_type && info->have_result == false ) + { + memcpy(info->dest_ptr, Addr, Net_GetAddressSize(AddrType)); + + info->have_result = true; + return 1; + } + return 0; +} + +int Net_Lookup_Addrs(const char *Name, void *cb_info, tNet_LookupAddrs_Callback *callback) { // 1. Load (if not loaded) the DNS config from "/Acess/Conf/dns" // - "* " for DNS server(s) @@ -53,33 +82,29 @@ int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr) for( int i = 0; i < giNumHostEntries; i ++ ) { const struct sHostEntry* he = &gaHostEntries[i]; - if( he->AddrType == AddrType ) + for( const char * const *namep = (const char**)he->Names; *namep; namep ++ ) { - for( const char * const *namep = (const char**)he->Names; *namep; namep ++ ) + if( strcasecmp(Name, *namep) == 0 ) { - if( strcasecmp(Name, *namep) == 0 ) - { - memcpy(Addr, he->AddrData, Net_GetAddressSize(AddrType)); + if( callback(cb_info, he->AddrType, he->AddrData) != 0 ) return 0; - } } } } // 3. Contact DNS server specified in config for( int i = 0; i < giNumDNSServers; i ++ ) { - // TODO const struct sDNSServer *s = &gaDNSServers[i]; struct sDNSCallbackInfo info = { - .expected_size = Net_GetAddressSize(AddrType), - .dest_ptr = Addr, + .cb_info = cb_info, + .callback = callback, .desired_type = TYPE_A, .desired_class = CLASS_IN, - .have_result = false + .got_value = false, }; if( ! DNS_Query(s->AddrType, s->AddrData, Name, info.desired_type, info.desired_class, int_DNS_callback, &info) ) { - if( info.have_result ) + if( info.got_value ) { return 0; } @@ -96,18 +121,30 @@ int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr) void int_DNS_callback(void *info_v, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) { struct sDNSCallbackInfo *info = info_v; - if( type == info->desired_type && class == info->desired_class && info->have_result == false ) + + // Check type matches (if pattern was provided) + if( info->desired_type != QTYPE_STAR && type != info->desired_type ) + return ; + if( info->desired_class != QCLASS_STAR && class != info->desired_class ) + return ; + + switch( type ) { - // We're just working with A and AAAA, so copying from rdata is safe - if( rdlength != info->expected_size ) { - // ... oh, that's not good + case TYPE_A: + if( rdlength != 4 ) return ; - } - - memcpy(info->dest_ptr, rdata, rdlength); - - info->have_result = true; + info->callback( info->cb_info, 4, rdata ); + break; + //case TYPE_AAAA: + // if( rdlength != 16 ) + // return ; + // info->callback( info->cb_info, 6, rdata ); + // break; + default: + // Ignore anything not A/AAAA + break; } + info->got_value = true; } int Net_Lookup_Name(int AddrType, const void *Addr, char *Dest[256]) diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h index 8a6ba440..62204f05 100644 --- a/Usermode/Libraries/libnet.so_src/include/dns.h +++ b/Usermode/Libraries/libnet.so_src/include/dns.h @@ -28,7 +28,7 @@ enum eClass { CLASS_IN, CLASS_CH, // "Chaos" - CLASS_STAR = 255, + QCLASS_STAR = 255, }; /** diff --git a/Usermode/Libraries/libnet.so_src/include_exp/net.h b/Usermode/Libraries/libnet.so_src/include_exp/net.h index f02c0a43..cd2cb6c8 100644 --- a/Usermode/Libraries/libnet.so_src/include_exp/net.h +++ b/Usermode/Libraries/libnet.so_src/include_exp/net.h @@ -72,6 +72,16 @@ extern int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RAddr, int LAd */ extern int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr); +/** + * \brief Callback for Net_Lookup_Addrs, returns non-zero when lookup should terminate + */ +typedef int tNet_LookupAddrs_Callback(void *info, int AddrType, const void *Addr); + +/** + * \brief Enumerate addresses for a host, calling the provided function for each + */ +extern int Net_Lookup_Addrs(const char *Name, void *info, tNet_LookupAddrs_Callback* callback); + /** */ extern int Net_Lookup_Name(int AddrType, const void *Addr, char *Dest[256]); diff --git a/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c b/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c index 5c21c06e..e1a0e424 100644 --- a/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c +++ b/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c @@ -13,6 +13,16 @@ #include // strtol #include +// === TYPES === +struct sLookupInfo { + struct addrinfo **ret_p; +}; + +// === PROTOTYPES === +struct addrinfo *int_new_addrinfo(int af, const void *addrdata); +int int_getaddinfo_lookupcb(void *info, int addr_type, const void *addr); + +// === GLOBALS === static const struct { const char *Name; int SockType; @@ -52,28 +62,20 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi { // 1. Check if the node is an IP address { - int type; char addrdata[16]; - type = Net_ParseAddress(node, addrdata); + int type = Net_ParseAddress(node, addrdata); switch(type) { - case 0: + case NET_ADDRTYPE_NULL: break; - case 4: // IPv4 - ret = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); - ret->ai_family = AF_INET; - ret->ai_socktype = 0; - ret->ai_protocol = 0; - ret->ai_addrlen = sizeof(struct in_addr); - ret->ai_addr = (void*)( ret + 1 ); - ret->ai_canonname = 0; - ret->ai_next = 0; - ((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET; - ((struct sockaddr_in*)ret->ai_addr)->sin_port = 0; - memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 ); + case NET_ADDRTYPE_IPV4: + ret = int_new_addrinfo(AF_INET, addrdata); + break; + case NET_ADDRTYPE_IPV6: + ret = int_new_addrinfo(AF_INET6, addrdata); break; default: - _SysDebug("getaddrinfo: Unknown address family %i", type); + _SysDebug("getaddrinfo: Unknown address type %i", type); return 1; } } @@ -82,15 +84,19 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi // - No luck with above, and hints->ai_flags doesn't have AI_NUMERICHOST set if( !ret && !(hints->ai_flags & AI_NUMERICHOST) ) { - _SysDebug("getaddrinfo: TODO DNS Lookups"); - // TODO: DNS Lookups - // ? /Acess/Conf/Nameservers - // ? /Acess/Conf/Hosts - //count = Net_LookupDNS(node, service, NULL); - // + // Just does a basic A record lookup + // TODO: Support SRV records + // TODO: Ensure that CNAMEs are handled correctly + struct sLookupInfo info = { + .ret_p = &ret, + }; + if( Net_Lookup_Addrs(node, &info, int_getaddinfo_lookupcb) ) { + // Lookup failed, quick return + return EAI_NONAME; + } } - // 3. No Match, chuck sad + // 3. No Match, return sad if( !ret ) { return EAI_NONAME; @@ -182,9 +188,81 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi return 0; } +/** + * \brief Allocate a new zeroed addrinfo for the specified address + */ +struct addrinfo *int_new_addrinfo(int af, const void *addrdata) +{ + size_t addrlen = 0; + switch(af) + { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; + default: + _SysDebug("int_new_addrinfo: ERROR - Unknown AF %i", af); + return NULL; + } + struct addrinfo* ret = malloc(sizeof(struct addrinfo) + addrlen); + ret->ai_family = af; + ret->ai_socktype = 0; + ret->ai_protocol = 0; + ret->ai_addrlen = addrlen; + ret->ai_addr = (void*)( ret + 1 ); + ret->ai_canonname = 0; + ret->ai_next = 0; + switch(af) + { + case AF_INET: + ((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET; + ((struct sockaddr_in*)ret->ai_addr)->sin_port = 0; + memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 ); + break; + case AF_INET6: + ((struct sockaddr_in6*)ret->ai_addr)->sin6_family = AF_INET6; + ((struct sockaddr_in6*)ret->ai_addr)->sin6_port = 0; + memcpy( &((struct sockaddr_in6*)ret->ai_addr)->sin6_addr, addrdata, 16 ); + break; + default: + _SysDebug("int_new_addrinfo: BUGCHECK - Unhandled AF %i", af); + return NULL; + } + return ret; +} + +// Callback for getaddrinfo's call to Net_Lookup_Addrs +int int_getaddinfo_lookupcb(void *info_v, int addr_type, const void *addr) +{ + struct sLookupInfo *info = info_v; + struct addrinfo *ent; + switch( addr_type ) + { + case NET_ADDRTYPE_IPV4: + ent = int_new_addrinfo(AF_INET, addr); + break; + case NET_ADDRTYPE_IPV6: + ent = int_new_addrinfo(AF_INET6, addr); + break; + default: + // Huh... unknown address type, just ignore it + return 0; + } + ent->ai_next = *info->ret_p; + *info->ret_p = ent; + return 0; +} + void freeaddrinfo(struct addrinfo *res) { - + while( res ) + { + struct addrinfo *next = res->ai_next; + free(res); + res = next; + } } int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) -- 2.20.1 From 508aa7d2f1f441ab4c9a7cc4540eb418bc2f9da7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 16 Feb 2015 14:32:12 +0800 Subject: [PATCH 02/16] Networking - DNS resolution semi-working --- KernelLand/Kernel/Makefile | 2 +- KernelLand/Modules/IPStack/udp.c | 160 ++++++++++++---- Usermode/Libraries/Makefile.tpl | 8 +- Usermode/Libraries/libnet.so_src/Makefile | 2 + Usermode/Libraries/libnet.so_src/TEST_dns.c | 52 +++++ Usermode/Libraries/libnet.so_src/dns.c | 177 +++++++++++++----- Usermode/Libraries/libnet.so_src/hostnames.c | 10 + .../Libraries/libnet.so_src/include/dns.h | 4 +- .../Libraries/libnet.so_src/include_exp/net.h | 4 + Usermode/Libraries/libnet.so_src/socket.c | 72 ++++++- 10 files changed, 399 insertions(+), 92 deletions(-) create mode 100644 Usermode/Libraries/libnet.so_src/TEST_dns.c diff --git a/KernelLand/Kernel/Makefile b/KernelLand/Kernel/Makefile index 34e6bcfd..895d90f9 100644 --- a/KernelLand/Kernel/Makefile +++ b/KernelLand/Kernel/Makefile @@ -153,7 +153,7 @@ $(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) $(MODS) arch/$(ARCHDIR) @echo "const char gsGitHash[] = \"$(_GITHASH)\";" >> $@ @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@ @echo "const char gsBuildInfo[] = \"Acess2 v$(KERNEL_VERSION) $(ARCH)-$(PLATFORM)\\\\r\\\\n\"" >> $@ - @echo " \"Build $(shell hostname --fqdn):$(BUILD_NUM) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@ + @echo " \"Build $(shell hostname --fqdn):$(BUILD_NUM) $(shell date +%FT%T%z) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@ # Compile rule for buildinfo (needs a special one because it's not a general source file) $(BUILDINFO_OBJ): $(BUILDINFO_SRC) @echo --- CC -o $@ diff --git a/KernelLand/Modules/IPStack/udp.c b/KernelLand/Modules/IPStack/udp.c index 67f60561..b9dd3231 100644 --- a/KernelLand/Modules/IPStack/udp.c +++ b/KernelLand/Modules/IPStack/udp.c @@ -67,13 +67,15 @@ void UDP_Initialise() int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer) { tUDPHeader *hdr = Buffer; - tUDPChannel *chan; - tUDPPacket *pack; - int len; - for(chan = List; chan; chan = chan->Next) + for(tUDPChannel *chan = List; chan; chan = chan->Next) { // Match local endpoint + LOG("(%p):%i - %s/%i:%i", + chan->Interface, chan->LocalPort, + IPStack_PrintAddress(chan->Remote.AddrType, &chan->Remote.Addr), chan->RemoteMask, + chan->Remote.Port + ); if(chan->Interface && chan->Interface != Interface) continue; if(chan->LocalPort != ntohs(hdr->DestPort)) continue; @@ -93,8 +95,8 @@ int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, in Log_Log("UDP", "Recieved packet for %p", chan); // Create the cached packet - len = ntohs(hdr->Length); - pack = malloc(sizeof(tUDPPacket) + len); + int len = ntohs(hdr->Length); + tUDPPacket *pack = malloc(sizeof(tUDPPacket) + len); pack->Next = NULL; memcpy(&pack->Remote.Addr, Address, IPStack_GetAddressSize(Interface->Type)); pack->Remote.Port = ntohs(hdr->SourcePort); @@ -159,7 +161,11 @@ void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, U { tUDPHeader hdr; - if(Channel->Interface && Channel->Interface->Type != AddrType) return ; + if(Channel->Interface && Channel->Interface->Type != AddrType) { + LOG("Bad interface type for channel packet, IF is %i, but packet is %i", + Channel->Interface->Type, AddrType); + return ; + } // Create the packet hdr.SourcePort = htons( Channel->LocalPort ); @@ -177,6 +183,7 @@ void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, U IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL); IPStack_Buffer_AppendSubBuffer(buffer, sizeof(hdr), 0, &hdr, NULL, NULL); // TODO: What if Channel->Interface is NULL here? + ASSERT(Channel->Interface); IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, buffer); break; default: @@ -205,49 +212,59 @@ tVFS_Node *UDP_Channel_Init(tInterface *Interface) return &new->Node; } -/** - * \brief Read from the channel file (wait for a packet) - */ -size_t UDP_Channel_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) +tUDPPacket *UDP_Channel_WaitForPacket(tUDPChannel *chan, Uint VFSFlags) { - tUDPChannel *chan = Node->ImplPtr; - tUDPPacket *pack; - tUDPEndpoint *ep; - int ofs, addrlen; - - if(chan->LocalPort == 0) { - Log_Notice("UDP", "Channel %p sent with no local port", chan); - return 0; - } - - while(chan->Queue == NULL) Threads_Yield(); + // EVIL - Yield until queue is created (avoids races) + while(chan->Queue == NULL) + Threads_Yield(); for(;;) { - tTime timeout_z = 0, *timeout = (Flags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL; - int rv = VFS_SelectNode(Node, VFS_SELECT_READ, timeout, "UDP_Channel_Read"); - if( rv ) { - errno = (Flags & VFS_IOFLAG_NOBLOCK) ? EWOULDBLOCK : EINTR; + tTime timeout_z = 0, *timeout = (VFSFlags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL; + int rv = VFS_SelectNode(&chan->Node, VFS_SELECT_READ, timeout, "UDP_Channel_Read"); + if( rv == 0 ) { + errno = (VFSFlags & VFS_IOFLAG_NOBLOCK) ? EWOULDBLOCK : EINTR; + return NULL; } SHORTLOCK(&chan->lQueue); if(chan->Queue == NULL) { SHORTREL(&chan->lQueue); continue; } - pack = chan->Queue; + tUDPPacket *pack = chan->Queue; chan->Queue = pack->Next; if(!chan->Queue) { chan->QueueEnd = NULL; - VFS_MarkAvaliable(Node, 0); // Nothing left + VFS_MarkAvaliable(&chan->Node, 0); // Nothing left } SHORTREL(&chan->lQueue); - break; + return pack; + } + // Unreachable +} + +/** + * \brief Read from the channel file (wait for a packet) + */ +size_t UDP_Channel_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) +{ + tUDPChannel *chan = Node->ImplPtr; + + if(chan->LocalPort == 0) { + Log_Notice("UDP", "Channel %p sent with no local port", chan); + return 0; + } + + tUDPPacket *pack = UDP_Channel_WaitForPacket(chan, Flags); + if( !pack ) { + return 0; } + size_t addrlen = IPStack_GetAddressSize(pack->Remote.AddrType); + tUDPEndpoint *ep = Buffer; + size_t ofs = 4 + addrlen; + // Check that the header fits - addrlen = IPStack_GetAddressSize(pack->Remote.AddrType); - ep = Buffer; - ofs = 4 + addrlen; if(Length < ofs) { free(pack); Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs); @@ -303,6 +320,8 @@ static const char *casIOCtls_Channel[] = { "getset_remoteport", "getset_remotemask", "set_remoteaddr", + "sendto", + "recvfrom", NULL }; /** @@ -354,14 +373,21 @@ int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data) case 6: // getset_remotemask (returns bool success) if(!Data) LEAVE_RET('i', chan->RemoteMask); - if(!CheckMem(Data, sizeof(int))) LEAVE_RET('i', -1); + if(!CheckMem(Data, sizeof(int))) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } if( !chan->Interface ) { LOG("Can't set remote mask on NULL interface"); LEAVE_RET('i', -1); } - if( *(int*)Data > IPStack_GetAddressSize(chan->Interface->Type) ) + int mask = *(int*)Data; + int addr_bits = IPStack_GetAddressSize(chan->Interface->Type) * 8; + if( mask > addr_bits ) { + LOG("Mask too large (%i > max %i)", mask, addr_bits); LEAVE_RET('i', -1); - chan->RemoteMask = *(int*)Data; + } + chan->RemoteMask = mask; LEAVE('i', chan->RemoteMask); return chan->RemoteMask; @@ -374,9 +400,73 @@ int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data) LOG("Invalid pointer"); LEAVE_RET('i', -1); } + LOG("Set remote addr %s", IPStack_PrintAddress(chan->Interface->Type, Data)); + chan->Remote.AddrType = chan->Interface->Type; memcpy(&chan->Remote.Addr, Data, IPStack_GetAddressSize(chan->Interface->Type)); LEAVE('i', 0); return 0; + case 8: { // sendto + if(!CheckMem(Data, 2*sizeof(void*)+2)) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } + const struct sSendToArgs { + const tUDPEndpoint* ep; + const void* buf; + const Uint16 buflen; + } info = *(const struct sSendToArgs*)Data; + LOG("sendto(buf=%p + %u, ep=%p)", info.buf, info.buflen, info.ep); + if(!CheckMem(info.ep, 2+2) || !CheckMem(info.ep, 2+2+IPStack_GetAddressSize(info.ep->AddrType)) ) { + LEAVE_RET('i', -1); + } + if(!CheckMem(info.buf, info.buflen)) { + LEAVE_RET('i', -1); + } + + UDP_SendPacketTo(chan, info.ep->AddrType, &info.ep->Addr, info.ep->Port, + info.buf, (size_t)info.buflen); + + LEAVE_RET('i', info.buflen); } + case 9: { // recvfrom + if(!CheckMem(Data, 2*sizeof(void*)+2)) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } + const struct sRecvFromArgs { + tUDPEndpoint* ep; + void* buf; + Uint16 buflen; + } info = *(const struct sRecvFromArgs*)Data; + LOG("recvfrom(buf=%p + %u, ep=%p)", info.buf, info.buflen, info.ep); + if(!CheckMem(info.ep, 2+2)) { + LEAVE_RET('i', -1); + } + if(!CheckMem(info.buf, info.buflen)) { + LEAVE_RET('i', -1); + } + + tUDPPacket *pack = UDP_Channel_WaitForPacket(chan, 0); + if( pack == NULL ) { + LOG("No packet"); + LEAVE_RET('i', 0); + } + + size_t addrsize = IPStack_GetAddressSize(pack->Remote.AddrType); + if( !CheckMem(info.ep, 2+2+addrsize) ) { + LOG("Insufficient space for source address"); + free(pack); + LEAVE_RET('i', -1); + } + info.ep->Port = pack->Remote.Port; + info.ep->AddrType = pack->Remote.AddrType; + memcpy(&info.ep->Addr, &pack->Remote.Addr, addrsize); + + size_t retlen = (info.buflen < pack->Length ? info.buflen : pack->Length); + memcpy(info.buf, pack->Data, retlen); + + free(pack); + + LEAVE_RET('i', retlen); } } LEAVE_RET('i', 0); } diff --git a/Usermode/Libraries/Makefile.tpl b/Usermode/Libraries/Makefile.tpl index 8f548bfa..3b8d2f55 100644 --- a/Usermode/Libraries/Makefile.tpl +++ b/Usermode/Libraries/Makefile.tpl @@ -60,17 +60,15 @@ _libs: $(HEADERS) .PHONY: utest utest-build utest-run $(UTESTS:%=runtest-%) -utest: utest-build generate_exp utest-run - -generate_exp: $(UTESTS:%=EXP_%.txt) +utest: utest-build utest-run utest-build: $(UTESTS:%=TEST_%) utest-run: $(UTESTS:%=runtest-%) -$(UTESTS:%=runtest-%): runtest-%: TEST_% EXP_%.txt +$(UTESTS:%=runtest-%): runtest-%: TEST_% @echo --- [TEST] $* - @./TEST_$* | diff EXP_$*.txt - + @./TEST_$* clean: $(RM) $(_BIN) $(_XBIN) $(OBJ) $(_BIN).dsm $(DEPFILES) $(EXTRACLEAN) diff --git a/Usermode/Libraries/libnet.so_src/Makefile b/Usermode/Libraries/libnet.so_src/Makefile index 00bb8783..10d5b962 100644 --- a/Usermode/Libraries/libnet.so_src/Makefile +++ b/Usermode/Libraries/libnet.so_src/Makefile @@ -10,4 +10,6 @@ OBJ = main.o address.o socket.o OBJ += hostnames.o dns.o BIN = libnet.so +UTESTS = dns + include ../Makefile.tpl diff --git a/Usermode/Libraries/libnet.so_src/TEST_dns.c b/Usermode/Libraries/libnet.so_src/TEST_dns.c new file mode 100644 index 00000000..26b36bf5 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/TEST_dns.c @@ -0,0 +1,52 @@ +/* + */ +#include "include/dns.h" +#include +#include +#include + +extern int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); + +// Complex response from "Q ssh.ucc.asn.au A IN" +const uint8_t test_packet_1[] = { + 0xac, 0x00, 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x03, 0x73, 0x73, 0x68, 0x03, 0x75, 0x63, 0x63, 0x03, 0x61, 0x73, 0x6e, 0x02, 0x61, 0x75, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x77, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x78, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x79, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x61, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x7a, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x62, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x75, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x76, 0xc0, 0x18, 0xc0, 0x2c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc0, 0x05, 0xc0, 0x3c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc2, 0x05, 0xc0, 0x4c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc4, 0x05, 0xc0, 0x5c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x3a, 0x41, 0xfe, 0x49, 0xc0, 0x6c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc6, 0x05, 0xc0, 0x7c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x3a, 0x41, 0xfd, 0x49, 0xc0, 0x8c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0xd3, 0x1d, 0x85, 0x20, 0xc0, 0x9c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0xca, 0x0c, 0x1f, 0x8d, + }; + +#define TEST_REL_INT(exp, rel, have) do { \ + int a = (exp);\ + int b = (have);\ + if( !(a rel b) ) { \ + fprintf(stderr, "TEST_REL_INT("#exp" "#rel" "#exp") FAILED l=%i r=%i", \ + a, b); \ + return 1; \ + } \ +} while(0) + +int test_response_parse_1_cb(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) +{ + int* stagep = info; + switch( *stagep ) + { + case 0: + TEST_REL_INT(0, ==, strcmp(name, "au.")); + break; + } + (*stagep) += 1; + return 0; +} +int test_response_parse_1(void) +{ + int stage = 0; + TEST_REL_INT(0, ==, DNS_int_ParseResponse(test_packet_1, sizeof(test_packet_1), &stage, test_response_parse_1_cb) ); + return 0; +} + +int main(void) +{ + int rv = 0; + // - Name Encode + // - Name Decode + // - Response parsing + rv |= test_response_parse_1(); + return rv; +} diff --git a/Usermode/Libraries/libnet.so_src/dns.c b/Usermode/Libraries/libnet.so_src/dns.c index 001ec000..518d4d47 100644 --- a/Usermode/Libraries/libnet.so_src/dns.c +++ b/Usermode/Libraries/libnet.so_src/dns.c @@ -9,14 +9,20 @@ #include // uint*_t #include // memcpy, strchr #include +#include // for _SysSelect +#include // FD_SET #include #include "include/dns.h" // === PROTOTYPES === +//int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info); +int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); size_t DNS_EncodeName(void *buf, const char *dotted_name); -int DNS_DecodeName(char dotted_name[256], const void *buf, size_t space); -int DNS_int_ParseRR(const void *buf, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p); +int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space); +int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p); + static uint16_t get16(const void *buf); +static uint32_t get32(const void *buf); static size_t put16(void *buf, uint16_t val); @@ -49,22 +55,42 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT int sock = Net_OpenSocket_UDP(ServerAType, ServerAddr, 53, 0); if( sock < 0 ) { // Connection failed + _SysDebug("DNS_Query - UDP open failed"); // TODO: Correctly report this failure with a useful error code return 1; } - int rv = _SysWrite(sock, packet, pos); + int rv = Net_UDP_SendTo(sock, 53, ServerAType, ServerAddr, pos, packet); if( rv != pos ) { + _SysDebug("DNS_Query - Write failed"); // TODO: Error reporting _SysClose(sock); return 1; } // - Wait - int return_len = 0; - do { - return_len = _SysRead(sock, packet, sizeof(packet)); - } while( return_len == 0 ); - if( return_len < 0 ) { + { + int nfd = sock + 1; + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + int64_t timeout = 2000; // Give it two seconds, should be long enough + rv = _SysSelect(nfd, &fds, NULL, NULL, &timeout, 0); + if( rv == 0 ) { + // Timeout with no reply, give up + _SysDebug("DNS_Query - Timeout"); + _SysClose(sock); + return 1; + } + if( rv < 0 ) { + // Oops, select failed + _SysDebug("DNS_Query - Select failure"); + _SysClose(sock); + return 1; + } + } + int return_len = Net_UDP_RecvFrom(sock, NULL, NULL, NULL, sizeof(packet), packet); + if( return_len <= 0 ) { // TODO: Error reporting + _SysDebug("DNS_Query - Read failure"); _SysClose(sock); return 1; } @@ -73,17 +99,33 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT // > TODO: Lock DNS queries // For each response in the answer (and additional) sections, call the passed callback + return DNS_int_ParseResponse(packet, return_len, info, handle_record); +} + +int DNS_int_ParseResponse(const void* buf, size_t return_len, void *info, handle_record_t* handle_record) +{ + const uint8_t* packet = buf; char rr_name[256]; + unsigned int id = get16(packet + 0); + if( id != 0xAC00 ) { + _SysDebug("DNS_Query - Packet ID mismatch"); + return 2; + } + unsigned int flags = get16(packet + 2); unsigned int qd_count = get16(packet + 4); unsigned int an_count = get16(packet + 6); unsigned int ns_count = get16(packet + 8); unsigned int ar_count = get16(packet + 10); - pos = 6*2; + size_t pos = 6*2; // TODO: Can I safely assert / fail if qd_count is non-zero? // - Questions, ignored for( unsigned int i = 0; i < qd_count; i ++ ) { - pos += DNS_DecodeName(NULL, packet + pos, return_len - pos); - pos += 2*2; + int rv = DNS_DecodeName(rr_name, packet, pos, return_len); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in QD"); + return 1; + } + pos += rv + 2*2; } // - Answers, pass on to handler for( unsigned int i = 0; i < an_count; i ++ ) @@ -92,20 +134,22 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT enum eClass class; uint32_t ttl; size_t rdlength; - int rv = DNS_int_ParseRR(packet + pos, return_len - pos, rr_name, &type, &class, &ttl, &rdlength); + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in AN"); return 1; } pos += rv; - handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos); + handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); } // Authority Records (should all be NS records) for( unsigned int i = 0; i < ns_count; i ++ ) { size_t rdlength; - int rv = DNS_int_ParseRR(packet + pos, return_len - pos, rr_name, NULL, NULL, NULL, &rdlength); + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, NULL, NULL, NULL, &rdlength); if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in NS"); return 1; } pos += rv; @@ -117,15 +161,16 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT enum eClass class; uint32_t ttl; size_t rdlength; - int rv = DNS_int_ParseRR(packet + pos, return_len - pos, rr_name, &type, &class, &ttl, &rdlength); + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in AR"); return 1; } pos += rv; - handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos); + handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); } - + return 0; } @@ -170,76 +215,124 @@ size_t DNS_EncodeName(void *buf, const char *dotted_name) } // Decode a name (including trailing . for root) -int DNS_DecodeName(char dotted_name[256], const void *buf, size_t space) +int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space) { int consumed = 0; int out_pos = 0; - const uint8_t *buf8 = buf; - while( *buf8 && space > 0 ) + const uint8_t *buf8 = (const uint8_t*)buf + ofs; + for( ;; ) { - if( consumed + 1 > space ) return -1; + if( ofs + consumed + 1 > space ) { + _SysDebug("DNS_DecodeName - Len byte OOR space=%i", space); + return -1; + } uint8_t seg_len = *buf8; buf8 ++; consumed ++; - // Protocol violation (overflowed end of buffer) - if( consumed + seg_len > space ) - return -1; + // Done + if( seg_len == 0 ) + break; + if( (seg_len & 0xC0) == 0xC0 ) + { + // Backreference, the rest of the name is a backref + char tmp[256]; + int ref_ofs = get16(buf8 - 1) & 0x3FFF; + consumed += 1, buf8 += 1; // Only one, previous inc still applies + _SysDebug("DNS_DecodeName - Nested at %i", ref_ofs); + if( DNS_DecodeName(tmp, buf, ref_ofs, space) < 0 ) + return -1; + memcpy(dotted_name+out_pos, tmp, strlen(tmp)); + out_pos += strlen(tmp); + break; + } // Protocol violation (segment too long) - if( seg_len >= 64 ) + if( seg_len >= 64 ) { + _SysDebug("DNS_DecodeName - Seg too long %i", seg_len); return -1; + } + // Protocol violation (overflowed end of buffer) + if( ofs + consumed + seg_len > space ) { + _SysDebug("DNS_DecodeName - Seg OOR %i+%i>%i", consumed, seg_len, space); + return -1; + } // Protocol violation (name was too long) - if( out_pos + seg_len + 1 > sizeof(dotted_name)-1 ) + if( out_pos + seg_len + 1 > 255 ) { + _SysDebug("DNS_DecodeName - Dotted name too long %i+%i+1 > %i", + out_pos, seg_len, 255); return -1; + } + + _SysDebug("DNS_DecodeName : Seg %i '%.*s'", seg_len, seg_len, buf8); // Read segment memcpy(dotted_name + out_pos, buf8, seg_len); buf8 += seg_len; consumed += seg_len; + out_pos += seg_len; // Place '.' - dotted_name[out_pos+seg_len+1] = '.'; - // Increment output counter - out_pos += seg_len + 1; + dotted_name[out_pos] = '.'; + out_pos ++; } - dotted_name[out_pos] = '\0'; + _SysDebug("DNS_DecodeName - '%s', consumed = %i", dotted_name, consumed); return consumed; } // Parse a Resource Record -int DNS_int_ParseRR(const void *buf, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p) +int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p) { const uint8_t *buf8 = buf; size_t consumed = 0; // 1. Name - int rv = DNS_DecodeName(name_p, buf8, space); + int rv = DNS_DecodeName(name_p, buf, ofs, space); if(rv < 0) return -1; - buf8 += rv, consumed += rv; + ofs += rv, consumed += rv; if( type_p ) - *type_p = get16(buf8); - buf8 += 2, consumed += 2; + *type_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; if( class_p ) - *class_p = get16(buf8); - buf8 += 2, consumed += 2; + *class_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; - return consumed; + if( ttl_p ) + *ttl_p = get32(buf + ofs); + ofs += 4, consumed += 4; + + size_t rdlength = get16(buf + ofs); + if( rdlength_p ) + *rdlength_p = rdlength; + ofs += 2, consumed += 2; + + _SysDebug("DNS_int_ParseRR - name='%s', rdlength=%i", name_p, rdlength); + + return consumed + rdlength; } static uint16_t get16(const void *buf) { const uint8_t* buf8 = buf; uint16_t rv = 0; - rv |= buf8[0]; - rv |= (uint16_t)buf8[1] << 8; + rv |= (uint16_t)buf8[0] << 8; + rv |= (uint16_t)buf8[1] << 0; + return rv; +} +static uint32_t get32(const void *buf) { + const uint8_t* buf8 = buf; + uint32_t rv = 0; + rv |= (uint32_t)buf8[0] << 24; + rv |= (uint32_t)buf8[1] << 16; + rv |= (uint32_t)buf8[2] << 8; + rv |= (uint32_t)buf8[3] << 0; return rv; } static size_t put16(void *buf, uint16_t val) { uint8_t* buf8 = buf; - buf8[0] = val & 0xFF; - buf8[1] = val >> 8; + buf8[0] = val >> 8; + buf8[1] = val & 0xFF; return 2; } diff --git a/Usermode/Libraries/libnet.so_src/hostnames.c b/Usermode/Libraries/libnet.so_src/hostnames.c index 88093de3..c3c96268 100644 --- a/Usermode/Libraries/libnet.so_src/hostnames.c +++ b/Usermode/Libraries/libnet.so_src/hostnames.c @@ -8,7 +8,9 @@ #include #include "include/dns.h" #include +#include // malloc (for loading config) #include +#include // _SysDebug // === TYPES === struct sDNSServer @@ -74,9 +76,16 @@ int int_lookupany_callback(void *info_v, int AddrType, const void *Addr) int Net_Lookup_Addrs(const char *Name, void *cb_info, tNet_LookupAddrs_Callback *callback) { + _SysDebug("Net_Lookup_Addrs(Name='%s')", Name); // 1. Load (if not loaded) the DNS config from "/Acess/Conf/dns" // - "* " for DNS server(s) // - "127.0.0.1 localhost localhost.localdomain" + if( !gaDNSServers ) + { + giNumDNSServers = 1; + gaDNSServers = malloc( 1 * sizeof(gaDNSServers[0]) ); + gaDNSServers[0].AddrType = Net_ParseAddress("192.168.1.1", gaDNSServers[0].AddrData); + } // 2. Check the hosts list for( int i = 0; i < giNumHostEntries; i ++ ) @@ -121,6 +130,7 @@ int Net_Lookup_Addrs(const char *Name, void *cb_info, tNet_LookupAddrs_Callback void int_DNS_callback(void *info_v, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) { struct sDNSCallbackInfo *info = info_v; + _SysDebug("int_DNS_callback(name='%s', type=%i, class=%i)", name, type, class); // Check type matches (if pattern was provided) if( info->desired_type != QTYPE_STAR && type != info->desired_type ) diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h index 62204f05..dc7a58b4 100644 --- a/Usermode/Libraries/libnet.so_src/include/dns.h +++ b/Usermode/Libraries/libnet.so_src/include/dns.h @@ -26,8 +26,8 @@ enum eTypes enum eClass { - CLASS_IN, - CLASS_CH, // "Chaos" + CLASS_IN = 1, + CLASS_CH = 3, // "Chaos" QCLASS_STAR = 255, }; diff --git a/Usermode/Libraries/libnet.so_src/include_exp/net.h b/Usermode/Libraries/libnet.so_src/include_exp/net.h index cd2cb6c8..3d33da03 100644 --- a/Usermode/Libraries/libnet.so_src/include_exp/net.h +++ b/Usermode/Libraries/libnet.so_src/include_exp/net.h @@ -6,6 +6,8 @@ #ifndef __LIBNET_H_ #define __LIBNET_H_ +#include + enum { NET_ADDRTYPE_NULL = 0, NET_ADDRTYPE_IPV4 = 4, @@ -58,6 +60,8 @@ extern int Net_OpenSocket(int AddrType, const void *Addr, const char *SocketName extern int Net_OpenSocket_TCPC(int AddrType, const void *Addr, int Port); extern int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RAddr, int LAddr); +extern int Net_UDP_SendTo (int FD, int Port, int AddrType, const void *Addr, size_t Length, const void *Data); +extern int Net_UDP_RecvFrom(int FD, int* Port, int* AddrType, void *Addr, size_t Length, void *Data); /** diff --git a/Usermode/Libraries/libnet.so_src/socket.c b/Usermode/Libraries/libnet.so_src/socket.c index 68335acc..825dc6fe 100644 --- a/Usermode/Libraries/libnet.so_src/socket.c +++ b/Usermode/Libraries/libnet.so_src/socket.c @@ -8,6 +8,7 @@ #include #include #include +#include // memcpy #include enum { @@ -15,6 +16,8 @@ enum { UDP_IOCTL_GETSETRPORT, UDP_IOCTL_GETSETRMASK, UDP_IOCTL_SETRADDR, + UDP_IOCTL_SENDTO, + UDP_IOCTL_RECVFROM, }; int Net_OpenSocket(int AddrType, const void *Addr, const char *Filename) @@ -50,10 +53,16 @@ int Net_OpenSocket_TCPC(int AddrType, const void *Addr, int Port) int fd = Net_OpenSocket(AddrType, Addr, "tcpc"); if( fd == -1 ) return -1; - _SysIOCtl(fd, 5, &Port); // Remote Port - _SysIOCtl(fd, 6, (void*)Addr); // Remote address (kernel shouldn't modify) - _SysIOCtl(fd, 7, NULL); // connect + if( _SysIOCtl(fd, 5, &Port) < 0 ) // Remote Port + goto err; + if( _SysIOCtl(fd, 6, (void*)Addr) < 0 ) // Remote address (kernel shouldn't modify) + goto err; + if( _SysIOCtl(fd, 7, NULL) < 0) // connect + goto err; return fd; +err: + _SysClose(fd); + return -1; } int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RPort, int LPort) @@ -61,11 +70,60 @@ int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RPort, int LPort) int fd = Net_OpenSocket(AddrType, Addr, "udp"); if( fd == -1 ) return -1; - _SysIOCtl(fd, UDP_IOCTL_GETSETLPORT, &LPort); // Remote Port + if( _SysIOCtl(fd, UDP_IOCTL_GETSETLPORT, &LPort) < 0 ) + goto err; + if( _SysIOCtl(fd, UDP_IOCTL_GETSETRPORT, &RPort) < 0 ) + goto err; int maskbits = Net_GetAddressSize(AddrType) * 8; - _SysIOCtl(fd, UDP_IOCTL_GETSETRPORT, &RPort); - _SysIOCtl(fd, UDP_IOCTL_GETSETRMASK, &maskbits); - _SysIOCtl(fd, UDP_IOCTL_SETRADDR, (void*)Addr); // Remote address (kernel shouldn't modify) + if( _SysIOCtl(fd, UDP_IOCTL_GETSETRMASK, &maskbits) < 0 ) + goto err; + if( _SysIOCtl(fd, UDP_IOCTL_SETRADDR, (void*)Addr) < 0 ) // Remote address (kernel shouldn't modify) + goto err; return fd; +err: + _SysClose(fd); + return -1; +} + +int Net_UDP_SendTo(int FD, int Port, int AddrType, const void *Addr, size_t Length, const void *Data) +{ + struct { + uint16_t port; + uint16_t addr_type; + char addr[16]; + } ep; + ep.port = Port; + ep.addr_type = AddrType; + memcpy(ep.addr, Addr, Net_GetAddressSize(AddrType)); + struct { + const void *ep; + const void *buf; + uint16_t len; + } info = { .ep = &ep, .buf = Data, .len = Length }; + + return _SysIOCtl(FD, UDP_IOCTL_SENDTO, &info); +} + +int Net_UDP_RecvFrom(int FD, int* Port, int* AddrType, void *Addr, size_t Length, void *Data) +{ + struct { + uint16_t port; + uint16_t addr_type; + char addr[16]; + } ep; + struct { + void *ep; + void *buf; + uint16_t len; + } info = { .ep = &ep, .buf = Data, .len = Length }; + + int rv = _SysIOCtl(FD, UDP_IOCTL_RECVFROM, &info); + if( rv > 0 ) + { + if(Port) *Port = ep.port; + if(AddrType) *AddrType = ep.addr_type; + if(Addr) memcpy(Addr, ep.addr, Net_GetAddressSize(ep.addr_type)); + } + return rv; } -- 2.20.1 From e14ac96d48bb4ef5cfc845e345df4770e1145ceb Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 16 Feb 2015 15:23:37 +0800 Subject: [PATCH 03/16] Modules/IPStack - Add structure for propagating ICMP errors --- KernelLand/Modules/IPStack/icmp.c | 7 +++- KernelLand/Modules/IPStack/ipstack.h | 11 +++++- KernelLand/Modules/IPStack/ipv4.c | 56 ++++++++++++++++++---------- KernelLand/Modules/IPStack/ipv4.h | 4 +- KernelLand/Modules/IPStack/ipv6.c | 6 +-- KernelLand/Modules/IPStack/ipv6.h | 2 +- KernelLand/Modules/IPStack/tcp.c | 26 ++++++++++++- KernelLand/Modules/IPStack/udp.c | 7 ++-- 8 files changed, 86 insertions(+), 33 deletions(-) diff --git a/KernelLand/Modules/IPStack/icmp.c b/KernelLand/Modules/IPStack/icmp.c index fa9927ee..f34d790f 100644 --- a/KernelLand/Modules/IPStack/icmp.c +++ b/KernelLand/Modules/IPStack/icmp.c @@ -26,7 +26,7 @@ struct { */ void ICMP_Initialise() { - IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket); + IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket, NULL); } /** @@ -64,12 +64,15 @@ void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buff { case 3: // Port Unreachable Log_Debug("ICMPv4", "Destination Unreachable (Port Unreachable)"); + IPv4_HandleError( Interface, IPERR_PORT_UNREACHABLE, + htons(Length)-sizeof(tICMPHeader), hdr->Data ); break; default: Log_Debug("ICMPv4", "Destination Unreachable (Code %i)", hdr->Code); + IPv4_HandleError( Interface, IPERR_MISC, + htons(Length)-sizeof(tICMPHeader), hdr->Data ); break; } -// IPv4_Unreachable( Interface, hdr->Code, htons(hdr->Length)-sizeof(tICMPHeader), hdr->Data ); break; // -- 8: Echo Request diff --git a/KernelLand/Modules/IPStack/ipstack.h b/KernelLand/Modules/IPStack/ipstack.h index ddcdde96..3833ce7b 100644 --- a/KernelLand/Modules/IPStack/ipstack.h +++ b/KernelLand/Modules/IPStack/ipstack.h @@ -15,7 +15,16 @@ typedef struct sAdapter tAdapter; typedef struct sInterface tInterface; typedef struct sSocketFile tSocketFile; -typedef void (*tIPCallback)(tInterface *Interface, void *Address, int Length, void *Buffer); +typedef enum eIPErrorMode +{ + IPERR_MISC, + IPERR_HOST_UNREACHABLE, + IPERR_PORT_UNREACHABLE, +} tIPErrorMode; + +// NOTE: Non-const to allow reuse of Rx buffer for prepping Tx +typedef void tIPRxCallback(tInterface *Interface, void *Address, int Length, void *Buffer); +typedef void tIPErrorCallback(tInterface *Interface, tIPErrorMode mode, const void *Address, int Length, const void *Buffer); enum eInterfaceTypes { AF_NULL, diff --git a/KernelLand/Modules/IPStack/ipv4.c b/KernelLand/Modules/IPStack/ipv4.c index 000fe396..371fe402 100644 --- a/KernelLand/Modules/IPStack/ipv4.c +++ b/KernelLand/Modules/IPStack/ipv4.c @@ -20,7 +20,7 @@ extern int ICMP_Ping(tInterface *Interface, tIPv4 Addr); // === PROTOTYPES === int IPv4_Initialise(); - int IPv4_RegisterCallback(int ID, tIPCallback Callback); +// int IPv4_RegisterCallback(int ID, tIPRxCallback Callback, ); void IPv4_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer); tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast); Uint32 IPv4_Netmask(int FixedBits); @@ -28,7 +28,10 @@ Uint16 IPv4_Checksum(const void *Buf, size_t Length); int IPv4_Ping(tInterface *Iface, tIPv4 Addr); // === GLOBALS === -tIPCallback gaIPv4_Callbacks[256]; +struct { + tIPRxCallback* rx_cb; + tIPErrorCallback* err_cb; +} gaIPv4_Callbacks[256]; // === CODE === /** @@ -46,11 +49,12 @@ int IPv4_Initialise() * \param ID 8-bit packet type ID * \param Callback Callback function */ -int IPv4_RegisterCallback(int ID, tIPCallback Callback) +int IPv4_RegisterCallback(int ID, tIPRxCallback *RxCallback, tIPErrorCallback *ErrCallback) { if( ID < 0 || ID > 255 ) return 0; - if( gaIPv4_Callbacks[ID] ) return 0; - gaIPv4_Callbacks[ID] = Callback; + if( gaIPv4_Callbacks[ID].rx_cb ) return 0; + gaIPv4_Callbacks[ID].rx_cb = RxCallback; + gaIPv4_Callbacks[ID].err_cb = ErrCallback; return 1; } @@ -66,14 +70,12 @@ int IPv4_RegisterCallback(int ID, tIPCallback Callback) */ int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPStackBuffer *Buffer) { - tMacAddr to; tIPv4Header hdr; - int length; - length = IPStack_Buffer_GetLength(Buffer); + int length = IPStack_Buffer_GetLength(Buffer); // --- Resolve destination MAC address - to = HWCache_Resolve(Iface, &Address); + tMacAddr to = HWCache_Resolve(Iface, &Address); if( MAC_EQU(to, cMAC_ZERO) ) { // No route to host Log_Notice("IPv4", "No route to host %i.%i.%i.%i", @@ -134,7 +136,6 @@ int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPS void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer) { tIPv4Header *hdr = Buffer; - tInterface *iface; Uint8 *data; int dataLength; int ret; @@ -197,7 +198,7 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff data = &hdr->Options[0]; // Get Interface (allowing broadcasts) - iface = IPv4_GetInterface(Adapter, hdr->Destination, 1); + tInterface *iface = IPv4_GetInterface(Adapter, hdr->Destination, 1); // Firewall rules if( iface ) { @@ -255,12 +256,29 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff } // Send it on - if( !gaIPv4_Callbacks[hdr->Protocol] ) { + if( !gaIPv4_Callbacks[hdr->Protocol].rx_cb ) { Log_Log("IPv4", "Unknown Protocol %i", hdr->Protocol); return ; } - gaIPv4_Callbacks[hdr->Protocol]( iface, &hdr->Source, dataLength, data ); + gaIPv4_Callbacks[hdr->Protocol].rx_cb( iface, &hdr->Source, dataLength, data ); +} + +/* + * Handles an error from the ICMPv4 code, 'Buf' contains part of an IPv4 packet + */ +void IPv4_HandleError(tInterface *Iface, tIPErrorMode Mode, size_t Length, const void *Buf) +{ + if(Length < sizeof(tIPv4Header)) return; + const tIPv4Header* hdr = Buf; + if(hdr->Version != 4) return; + + // Get Data and Data Length + size_t dataLength = MIN(Length, ntohs(hdr->TotalLength)) - sizeof(tIPv4Header); + const void *data = &hdr->Options[0]; + + if( gaIPv4_Callbacks[hdr->Protocol].err_cb ) + gaIPv4_Callbacks[hdr->Protocol].err_cb(Iface, Mode, &hdr->Source, dataLength, data); } /** @@ -272,16 +290,14 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff */ tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast) { - tInterface *iface = NULL, *zero_iface = NULL; - Uint32 netmask; - Uint32 addr, this; + tInterface *zero_iface = NULL; ENTER("pAdapter xAddress bBroadcast", Adapter, Address, Broadcast); - addr = ntohl( Address.L ); + Uint32 addr = ntohl( Address.L ); LOG("addr = 0x%x", addr); - for( iface = gIP_Interfaces; iface; iface = iface->Next) + for( tInterface *iface = gIP_Interfaces; iface; iface = iface->Next) { if( iface->Adapter != Adapter ) continue; if( iface->Type != 4 ) continue; @@ -307,8 +323,8 @@ tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast) if( !Broadcast ) continue; // Check for broadcast - this = ntohl( ((tIPv4*)iface->Address)->L ); - netmask = IPv4_Netmask(iface->SubnetBits); + Uint32 this = ntohl( ((tIPv4*)iface->Address)->L ); + Uint32 netmask = IPv4_Netmask(iface->SubnetBits); LOG("iface addr = 0x%x, netmask = 0x%x (bits = %i)", this, netmask, iface->SubnetBits); if( (addr & netmask) == (this & netmask) && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) ) diff --git a/KernelLand/Modules/IPStack/ipv4.h b/KernelLand/Modules/IPStack/ipv4.h index dd78788f..c31b7512 100644 --- a/KernelLand/Modules/IPStack/ipv4.h +++ b/KernelLand/Modules/IPStack/ipv4.h @@ -47,9 +47,11 @@ struct sIPv4Header #define IPV4_ETHERNET_ID 0x0800 // === FUNCTIONS === -extern int IPv4_RegisterCallback(int ID, tIPCallback Callback); +extern int IPv4_RegisterCallback(int ID, tIPRxCallback *RxCallback, tIPErrorCallback *ErrCallback); extern Uint16 IPv4_Checksum(const void *Buf, size_t Length); extern Uint32 IPv4_Netmask(int FixedBits); extern int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPStackBuffer *Buffer); +extern void IPv4_HandleError(tInterface *Iface, tIPErrorMode Mode, size_t Length, const void *Buf); + #endif diff --git a/KernelLand/Modules/IPStack/ipv6.c b/KernelLand/Modules/IPStack/ipv6.c index 2ac05747..0e6df538 100644 --- a/KernelLand/Modules/IPStack/ipv6.c +++ b/KernelLand/Modules/IPStack/ipv6.c @@ -14,12 +14,12 @@ extern Uint32 IPv4_Netmask(int FixedBits); // === PROTOTYPES === int IPv6_Initialise(); - int IPv6_RegisterCallback(int ID, tIPCallback Callback); +// int IPv6_RegisterCallback(int ID, tIPCallback Callback); void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer); tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast); // === GLOBALS === -tIPCallback gaIPv6_Callbacks[256]; +tIPRxCallback* gaIPv6_Callbacks[256]; // === CODE === /** @@ -36,7 +36,7 @@ int IPv6_Initialise() * \param ID 8-bit packet type ID * \param Callback Callback function */ -int IPv6_RegisterCallback(int ID, tIPCallback Callback) +int IPv6_RegisterCallback(int ID, tIPRxCallback* Callback) { if( ID < 0 || ID > 255 ) return 0; if( gaIPv6_Callbacks[ID] ) return 0; diff --git a/KernelLand/Modules/IPStack/ipv6.h b/KernelLand/Modules/IPStack/ipv6.h index fec00f75..086dfbb5 100644 --- a/KernelLand/Modules/IPStack/ipv6.h +++ b/KernelLand/Modules/IPStack/ipv6.h @@ -37,7 +37,7 @@ struct sIPv6Header #define IPV6_ETHERNET_ID 0x86DD -extern int IPv6_RegisterCallback(int ID, tIPCallback Callback); +extern int IPv6_RegisterCallback(int ID, tIPRxCallback* Callback); extern int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, tIPStackBuffer *Buffer); #endif diff --git a/KernelLand/Modules/IPStack/tcp.c b/KernelLand/Modules/IPStack/tcp.c index a8a059ac..2854f30a 100644 --- a/KernelLand/Modules/IPStack/tcp.c +++ b/KernelLand/Modules/IPStack/tcp.c @@ -28,6 +28,7 @@ void TCP_StartConnection(tTCPConnection *Conn); void TCP_SendPacket(tTCPConnection *Conn, tTCPHeader *Header, size_t DataLen, const void *Data); void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Header, size_t Length, const void *Data); void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); +void TCP_IPError(tInterface *Interface, tIPErrorMode Mode, const void *Address, int Length, const void *Buffer); int TCP_INT_HandleServerPacket(tInterface *Interface, tTCPListener *Server, const void *Address, tTCPHeader *Header, size_t Length); int TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length); int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length); @@ -94,7 +95,7 @@ void TCP_Initialise(void) giTCP_NextOutPort += rand()%128; IPStack_AddFile(&gTCP_ServerFile); IPStack_AddFile(&gTCP_ClientFile); - IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); + IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket, TCP_IPError); IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); } @@ -304,6 +305,29 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe } } +void TCP_IPError(tInterface *Interface, tIPErrorMode Mode, const void *Address, int Length, const void *Buffer) +{ + if( Length < sizeof(tTCPHeader) ) return ; + + const tTCPHeader *hdr = Buffer; + + // TODO: Handle errors for server connections + + for( tTCPConnection *conn = gTCP_OutbountCons; conn; conn = conn->Next ) + { + if(conn->Interface != Interface) + continue; + if(conn->RemotePort != ntohs(hdr->SourcePort)) + continue; + if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 ) + continue ; + + // Mark an error on the interface + VFS_MarkError(&conn->Node, 1); + return ; + } +} + /* * Handle packets in LISTEN state */ diff --git a/KernelLand/Modules/IPStack/udp.c b/KernelLand/Modules/IPStack/udp.c index b9dd3231..9037439c 100644 --- a/KernelLand/Modules/IPStack/udp.c +++ b/KernelLand/Modules/IPStack/udp.c @@ -15,7 +15,7 @@ // === PROTOTYPES === void UDP_Initialise(); void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); -void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer); +void UDP_IPError(tInterface *Interface, tIPErrorMode Code, const void *Address, int Length, const void *Buffer); void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length); // --- Client Channels tVFS_Node *UDP_Channel_Init(tInterface *Interface); @@ -56,8 +56,7 @@ tSocketFile gUDP_SocketFile = {NULL, "udp", UDP_Channel_Init}; void UDP_Initialise() { IPStack_AddFile(&gUDP_SocketFile); - //IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket, UDP_Unreachable); - IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket); + IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket, UDP_IPError); } /** @@ -146,7 +145,7 @@ void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe /** * \brief Handle an ICMP Unrechable Error */ -void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer) +void UDP_IPError(tInterface *Interface, tIPErrorMode Code, const void *Address, int Length, const void *Buffer) { } -- 2.20.1 From c58f6a057d31ee2c2be3b41b8ff17c4a3dcb9c4f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 16 Feb 2015 15:24:02 +0800 Subject: [PATCH 04/16] Usermode/libnet - Set recursion bit (We want the server to do as much as possible for us) --- Usermode/Libraries/libnet.so_src/dns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Usermode/Libraries/libnet.so_src/dns.c b/Usermode/Libraries/libnet.so_src/dns.c index 518d4d47..3bb9c355 100644 --- a/Usermode/Libraries/libnet.so_src/dns.c +++ b/Usermode/Libraries/libnet.so_src/dns.c @@ -36,7 +36,7 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT assert( (6*2) + (namelen + 2*2) < 512 ); // - Header pos += put16(packet + pos, 0xAC00); // Identifier (arbitary) - pos += put16(packet + pos, (0 << 0) | (0 << 1) ); // Op : Query, Standard, no other flags + pos += put16(packet + pos, (0 << 0) | (0 << 1) | (1 << 8) ); // Op : Query, Standard, Recursion pos += put16(packet + pos, 1); // QDCount pos += put16(packet + pos, 0); // ANCount pos += put16(packet + pos, 0); // NSCount -- 2.20.1 From 67a7fe2bb79eceaf10c572a99bd8345c4e81cf5b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 16 Feb 2015 16:51:24 +0800 Subject: [PATCH 05/16] Modules/Tegra2Vid - Misc --- KernelLand/Modules/Display/Tegra2Vid/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/KernelLand/Modules/Display/Tegra2Vid/main.c b/KernelLand/Modules/Display/Tegra2Vid/main.c index 20fdb8d5..9ca70984 100644 --- a/KernelLand/Modules/Display/Tegra2Vid/main.c +++ b/KernelLand/Modules/Display/Tegra2Vid/main.c @@ -70,11 +70,13 @@ inline void _dumpreg(int i) Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x (%s)", i, gpTegra2Vid_IOMem[i], (csaTegra2Vid_RegisterNames[i] ? csaTegra2Vid_RegisterNames[i] : "-")); } +#define DUMPREGS(s,e) do{for(int ii=(s);ii<=(e);ii++) _dumpreg(ii);}while(0) void Tegra2Vid_int_DumpRegisters(void) { Log_Debug("Tegra2Vid", "Display CMD Registers"); - for( int i = 0x000; i <= 0x01A; i ++ ) _dumpreg(i); + DUMPREGS(0x000, 0x01A); // 00 -- 1A :: CMD (block 1) + DUMPREGS(0x028, 0x043); // 28 -- 43 :: CMD (block 2) for( int i = 0x028; i <= 0x043; i ++ ) _dumpreg(i); Log_Debug("Tegra2Vid", "Display COM Registers"); for( int i = 0x300; i <= 0x329; i ++ ) _dumpreg(i); @@ -112,6 +114,7 @@ int Tegra2Vid_Install(char **Arguments) #endif #if 0 + // Map the original framebuffer into memory and write to it (tests the original state) giTegra2Vid_FramebufferSize = (gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]&0xFFFF) *(gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]>>16)*4; @@ -359,6 +362,7 @@ int Tegra2Vid_int_SetMode(int Mode) if( gpTegra2Vid_Framebuffer ) { // TODO: Free framebuffer for reallocation + Log_Error("Tegra2Vid", "TODO: Free existing framebuffer"); } giTegra2Vid_FramebufferSize = w*h*4; -- 2.20.1 From 5b99c972f3994cd19a04ac57caaf20da96a6aa14 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 16 Feb 2015 18:02:09 +0800 Subject: [PATCH 06/16] Build - Fix build quirks for fresh --- Externals/cross-compiler/Makefile | 2 +- Makefile | 3 ++- Usermode/Libraries/Makefile.tpl | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Externals/cross-compiler/Makefile b/Externals/cross-compiler/Makefile index ae2df5ae..935d6465 100644 --- a/Externals/cross-compiler/Makefile +++ b/Externals/cross-compiler/Makefile @@ -35,7 +35,7 @@ $(BDIR_GCC)/Makefile: Makefile $(addprefix $(GCC_DIR)/,$(GCC_CHANGES)) $(GCC_DIR $(PREFIX)/bin/$(TARGET)-gcc: $(BDIR_GCC)/Makefile @$(ENVVARS) make -C $(BDIR_GCC) $(GCC_TARGETS:%=all-%) -j $(PARLEVEL) - @$(ENVVARS) make -C $(BDIR_GCC)libstdc++-v3/ all-target-libsupc++ -j $(PARLEVEL) + #@$(ENVVARS) make -C $(BDIR_GCC)/libstdc++-v3/ all-target-libsupc++ -j $(PARLEVEL) @$(ENVVARS) make -C $(BDIR_GCC) $(GCC_TARGETS:%=install-%) diff --git a/Makefile b/Makefile index a2e46d10..cb21b454 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ SUBMAKE = $(MAKE) --no-print-directory -USRLIBS := crt0.o ld-acess.so libc.so libposix.so libc++.so +USRLIBS := crt0.o ld-acess.so libc.so libposix.so libc++.so libpthread.so USRLIBS += libreadline.so libnet.so liburi.so libpsocket.so USRLIBS += libimage_sif.so libunicode.so libm.so USRLIBS += libaxwin4.so @@ -136,5 +136,6 @@ $(CC): @echo --- @echo $(CC) does not exist, recompiling @echo --- + for dir in $(USRLIBS:%=Usermode/Libraries/%_src); do $(SUBMAKE) -C $$dir _libs; done make -C Externals/cross-compiler/ -f Makefile.cross endif diff --git a/Usermode/Libraries/Makefile.tpl b/Usermode/Libraries/Makefile.tpl index 3b8d2f55..de263f52 100644 --- a/Usermode/Libraries/Makefile.tpl +++ b/Usermode/Libraries/Makefile.tpl @@ -55,6 +55,7 @@ HEADERS := $(patsubst include_exp/%,../../include/%,$(shell find include_exp/ -n _libs: $(HEADERS) ../../include/%: include_exp/% + @echo [LN] $@ @mkdir -p $(dir $@) @ln -s $(shell pwd)/$< $@ -- 2.20.1 From 93d0cdaafdf1edc4af1270e04bdb97159a51a30f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 10:50:06 +0800 Subject: [PATCH 07/16] Kernel/ARMv7 - Hacky (non-atomic) sync_and_fetch_4 --- KernelLand/Kernel/arch/armv7/lib.S | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/KernelLand/Kernel/arch/armv7/lib.S b/KernelLand/Kernel/arch/armv7/lib.S index e2f06130..554d7a11 100644 --- a/KernelLand/Kernel/arch/armv7/lib.S +++ b/KernelLand/Kernel/arch/armv7/lib.S @@ -82,3 +82,11 @@ __divmod32_asm: pop {r4} mov pc, lr +.globl __sync_fetch_and_and_4 +__sync_fetch_and_and_4: + mov r2, r0 + ldr r0, [r2] + mov r3, r0 + and r3, r1 + str r3, [r2] + mov pc, lr -- 2.20.1 From 7e9bbefbdcbfdba27eb6cdacae0811f428483892 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 10:50:34 +0800 Subject: [PATCH 08/16] Kernel/x86 - (minor) Fix spaces in log output on ZERO page --- KernelLand/Kernel/arch/x86/mm_virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KernelLand/Kernel/arch/x86/mm_virt.c b/KernelLand/Kernel/arch/x86/mm_virt.c index 80875185..01843d9c 100644 --- a/KernelLand/Kernel/arch/x86/mm_virt.c +++ b/KernelLand/Kernel/arch/x86/mm_virt.c @@ -311,7 +311,7 @@ void MM_DumpTables_Print(tVAddr Start, Uint32 Orig, size_t Size, void *Node) { if( (Orig & ~(PAGE_SIZE-1)) == giMM_ZeroPage ) { - Log( "0x%08x => ZERO + 0x%08x (%s%s%s%s%s) %p", + Log(" 0x%08x => ZERO + 0x%08x (%s%s%s%s%s) %p", Start, Size, (Orig & PF_NOPAGE ? "P" : "-"), -- 2.20.1 From 98bd9c0c8985c50c42231c116a4e18fedd47761e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 10:56:54 +0800 Subject: [PATCH 09/16] Kernel/debug - Clean up Debug() method, bind to #define config --- KernelLand/Kernel/debug.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/KernelLand/Kernel/debug.c b/KernelLand/Kernel/debug.c index eed38de5..3db53876 100644 --- a/KernelLand/Kernel/debug.c +++ b/KernelLand/Kernel/debug.c @@ -8,7 +8,7 @@ #define DEBUG_MAX_LINE_LEN 256 #define LOCK_DEBUG_OUTPUT 0 // Avoid interleaving of output lines? -#define TRACE_TO_KTERM 0 // Send ENTER/DEBUG/LEAVE to debug? +#define TRACE_TO_KTERM 0 // Send ENTER/DEBUG/LEAVE/Debug to the VTerm // === IMPORTS === extern void KernelPanic_SetMode(void); @@ -19,7 +19,6 @@ extern void VT_SetTerminal(int TerminalID); // === PROTOTYPES === static void Debug_Putchar(char ch); static void Debug_Puts(int bUseKTerm, const char *Str); -void Debug_DbgOnlyFmt(const char *format, va_list args); void Debug_FmtS(int bUseKTerm, const char *format, ...); bool Debug_Fmt(int bUseKTerm, const char *format, va_list args); void Debug_SetKTerminal(const char *File); @@ -85,11 +84,6 @@ static void Debug_Puts(int UseKTerm, const char *Str) } } -void Debug_DbgOnlyFmt(const char *format, va_list args) -{ - Debug_Fmt(0, format, args); -} - bool Debug_Fmt(int bUseKTerm, const char *format, va_list args) { char buf[DEBUG_MAX_LINE_LEN]; @@ -166,12 +160,11 @@ void Debug(const char *Fmt, ...) SHORTLOCK(&glDebug_Lock); #endif - Debug_Puts(0, "Debug: "); + Debug_Puts(TRACE_TO_KTERM, "Debug: "); va_start(args, Fmt); - Debug_DbgOnlyFmt(Fmt, args); + Debug_Fmt(TRACE_TO_KTERM, Fmt, args); va_end(args); - Debug_PutCharDebug('\r'); - Debug_PutCharDebug('\n'); + Debug_Puts(TRACE_TO_KTERM, "\r\n"); #if LOCK_DEBUG_OUTPUT SHORTREL(&glDebug_Lock); #endif -- 2.20.1 From 9eadc33399e705035c33e8434a9644d91e44ed44 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 11:03:33 +0800 Subject: [PATCH 10/16] Kernel/VTerm - Minor cleanup to VT input (remove logging) --- KernelLand/Kernel/drv/vterm_input.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/KernelLand/Kernel/drv/vterm_input.c b/KernelLand/Kernel/drv/vterm_input.c index aa517d9d..15da798e 100644 --- a/KernelLand/Kernel/drv/vterm_input.c +++ b/KernelLand/Kernel/drv/vterm_input.c @@ -75,6 +75,9 @@ void VT_KBCallBack(Uint32 Codepoint) switch(term->RawScancode) { + case KEYSYM_DELETE: + // TODO: Reboot, or poke secure registered app + return; case KEYSYM_F1 : VT_SetTerminal(0); return; case KEYSYM_F2 : VT_SetTerminal(1); return; case KEYSYM_F3 : VT_SetTerminal(2); return; @@ -106,9 +109,7 @@ void VT_KBCallBack(Uint32 Codepoint) case KEYSYM_PGUP: if( term->Flags & VT_FLAG_ALTBUF ) return ; - Log_Debug("VTerm", "ScrollUp - Old=%i, step=%i", term->ViewTopRow, scroll_step); term->ViewTopRow = (term->ViewTopRow > scroll_step ? term->ViewTopRow - scroll_step : 0); - Log_Debug("VTerm", "ScrollUp - New=%i", term->ViewTopRow); VT_int_UpdateScreen(term, 1); return; // - View down (text goes up) @@ -116,9 +117,7 @@ void VT_KBCallBack(Uint32 Codepoint) if( term->Flags & VT_FLAG_ALTBUF ) return ; - Log_Debug("VTerm", "ScrollDown - Old=%i, max=%i", term->ViewTopRow, scroll_max); term->ViewTopRow = MIN(term->ViewTopRow + scroll_step, scroll_max); - Log_Debug("VTerm", "ScrollDown - New=%i", term->ViewTopRow); VT_int_UpdateScreen(term, 1); return; } -- 2.20.1 From 4a24c4eae72aa807cac8b3dc3c701323373babb6 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 11:29:21 +0800 Subject: [PATCH 11/16] Usermode/ld-acess - Clean up loadlib.c, improved debug --- Usermode/Libraries/ld-acess.so_src/common.h | 7 ++++ Usermode/Libraries/ld-acess.so_src/export.c | 13 +----- Usermode/Libraries/ld-acess.so_src/loadlib.c | 42 ++++++++++---------- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/Usermode/Libraries/ld-acess.so_src/common.h b/Usermode/Libraries/ld-acess.so_src/common.h index e0620c26..af620be6 100644 --- a/Usermode/Libraries/ld-acess.so_src/common.h +++ b/Usermode/Libraries/ld-acess.so_src/common.h @@ -18,6 +18,8 @@ typedef uint8_t Uint8; typedef uint16_t Uint16; typedef uint32_t Uint32; +#define ASSERT(cnd) do { if( !(cnd) ) { _SysDebug("ASSERT: "#cnd" failed"); *(volatile int*)1 = 123; } } while(0) + // HACK: Replace with underscored #define SysDebug _SysDebug @@ -32,6 +34,11 @@ typedef struct { char *Name; } tLoadedLib; +typedef struct { + void *Value; + const char *Name; +} tLocalExport; + // === GLOBALS === extern tLoadedLib gLoadedLibraries[MAX_LOADED_LIBRARIES]; diff --git a/Usermode/Libraries/ld-acess.so_src/export.c b/Usermode/Libraries/ld-acess.so_src/export.c index e40dd8eb..5a7e6e0d 100644 --- a/Usermode/Libraries/ld-acess.so_src/export.c +++ b/Usermode/Libraries/ld-acess.so_src/export.c @@ -26,10 +26,7 @@ extern void _ZN4_sys5debugEPKcz(const char *,...); // C++ "_sys::debug" used by #define SYSCALL6(name,num) EXP(name), // === CONSTANTS === -const struct { - void *Value; - char *Name; -} caLocalExports[] = { +const tLocalExport caLocalExports[] = { EXP(gLoadedLibraries), EXP(_errno), EXP(ldacess_DumpLoadedLibraries), @@ -44,14 +41,6 @@ const struct { {0, "__cxa_type_match"}, {0, "__cxa_begin_cleanup"}, #endif -#if 0 - EXP(__umoddi3), - EXP(__udivdi3), - EXP(__divsi3), - EXP(__modsi3), - EXP(__udivsi3), - EXP(__umodsi3) -#endif }; const int ciNumLocalExports = sizeof(caLocalExports)/sizeof(caLocalExports[0]); diff --git a/Usermode/Libraries/ld-acess.so_src/loadlib.c b/Usermode/Libraries/ld-acess.so_src/loadlib.c index 31dcbd8a..2a083030 100644 --- a/Usermode/Libraries/ld-acess.so_src/loadlib.c +++ b/Usermode/Libraries/ld-acess.so_src/loadlib.c @@ -18,10 +18,7 @@ #define MAX_QUEUED_ENTRYPOINTS 8 // === IMPORTS === -extern const struct { - void *Value; - char *Name; -} caLocalExports[]; +extern const tLocalExport caLocalExports[]; extern const int ciNumLocalExports; extern char **gEnvP; extern char gLinkedBase[]; @@ -48,11 +45,9 @@ void ldacess_DumpLoadedLibraries(void) { for( int i = 0; i < MAX_LOADED_LIBRARIES; i ++ ) { - if(gLoadedLibraries[i].Base == 0) break; // Last entry has Base set to NULL - _SysDebug("%p: %s", - gLoadedLibraries[i].Base, - gLoadedLibraries[i].Name - ); + const tLoadedLib* ll = &gLoadedLibraries[i]; + if(ll->Base == 0) break; // Last entry has Base set to NULL + _SysDebug("%p: %s", ll->Base, ll->Name); } } @@ -150,7 +145,6 @@ void *LoadLibrary(const char *SoName, const char *SearchDir, char **envp) */ void *IsFileLoaded(const char *file) { - int i; DEBUGS("IsFileLoaded: (file='%s')", file); // Applications link against either libld-acess.so or ld-acess.so @@ -161,7 +155,7 @@ void *IsFileLoaded(const char *file) return &gLinkedBase; } - for( i = 0; i < MAX_LOADED_LIBRARIES; i++ ) + for( int i = 0; i < MAX_LOADED_LIBRARIES; i++ ) { if(gLoadedLibraries[i].Base == 0) break; // Last entry has Base set to NULL DEBUGS(" strcmp('%s', '%s')", gLoadedLibraries[i].Name, file); @@ -216,7 +210,6 @@ void AddLoaded(const char *File, void *base) */ void Unload(void *Base) { - int i, j; int id; char *str; for( id = 0; id < MAX_LOADED_LIBRARIES; id++ ) @@ -231,8 +224,8 @@ void Unload(void *Base) str = gLoadedLibraries[id].Name; // Compact Loaded List - j = id; - for( i = j + 1; i < MAX_LOADED_LIBRARIES; i++, j++ ) + int j = id; + for( int i = j + 1; i < MAX_LOADED_LIBRARIES; i++, j++ ) { if(gLoadedLibraries[i].Base == 0) break; // Compact String @@ -256,14 +249,18 @@ void Unload(void *Base) */ int GetSymbol(const char *name, void **Value, size_t *Size, void *IgnoreBase) { + ASSERT(name); + ASSERT(Value); + ASSERT(Size); //SysDebug("GetSymbol: (%s)"); for( int i = 0; i < ciNumLocalExports; i ++ ) { - if( strcmp(caLocalExports[i].Name, name) == 0 ) { - *Value = caLocalExports[i].Value; + const tLocalExport* le = &caLocalExports[i]; + if( strcmp(le->Name, name) == 0 ) { + *Value = le->Value; if(Size) *Size = 0; - //SysDebug("GetSymbol: Local %p+0x%x", *Value, 0); + DEBUGS("'%s' = Local %p+%#x", name, le->Value, 0); return 1; } } @@ -271,31 +268,34 @@ int GetSymbol(const char *name, void **Value, size_t *Size, void *IgnoreBase) bool have_weak = false; for(int i = 0; i < MAX_LOADED_LIBRARIES && gLoadedLibraries[i].Base != 0; i ++) { + const tLoadedLib* ll = &gLoadedLibraries[i]; // Allow ignoring the current module - if( gLoadedLibraries[i].Base == IgnoreBase ) { + if( ll->Base == IgnoreBase ) { //SysDebug("GetSymbol: Ignore %p", gLoadedLibraries[i].Base); continue ; } - //SysDebug(" GetSymbol: Trying 0x%x, '%s'", - // gLoadedLibraries[i].Base, gLoadedLibraries[i].Name); + //SysDebug(" GetSymbol: Trying 0x%x, '%s'", ll->Base, ll->Name); void *tmpval; size_t tmpsize; - int rv = GetSymbolFromBase(gLoadedLibraries[i].Base, name, &tmpval, &tmpsize); + int rv = GetSymbolFromBase(ll->Base, name, &tmpval, &tmpsize); if(rv) { *Value = tmpval; *Size = tmpsize; if( rv == 1 ) { + DEBUGS("'%s' = %p '%s' Strong %p+%#x", name, ll->Base, ll->Name, *Value, *Size); return 1; } have_weak = true; } } if(have_weak) { + DEBUGS("'%s' = Weak %p+%#x", name, *Value, *Size); return 2; } else { + DEBUGS("'%s' = ?", name); return 0; } } -- 2.20.1 From bdab8e5cebaf249d291d19523d0358f8c1c98008 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 11:32:03 +0800 Subject: [PATCH 12/16] Kernel/threads - Debug cleanups and (hopefully) race avoidance --- KernelLand/Kernel/include/threads_int.h | 1 + KernelLand/Kernel/threads.c | 29 ++++++++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/KernelLand/Kernel/include/threads_int.h b/KernelLand/Kernel/include/threads_int.h index 403a2eff..1c9a08d7 100644 --- a/KernelLand/Kernel/include/threads_int.h +++ b/KernelLand/Kernel/include/threads_int.h @@ -143,6 +143,7 @@ static const char * const casTHREAD_STAT[] = { "THREAD_STAT_DEAD", "THREAD_STAT_BURIED" }; +static const unsigned int ciTHREAD_STAT_COUNT = sizeof(casTHREAD_STAT)/sizeof(casTHREAD_STAT[0]); // === GLOBALS === extern BOOL gaThreads_NoTaskSwitch[MAX_CPUS]; diff --git a/KernelLand/Kernel/threads.c b/KernelLand/Kernel/threads.c index 469c5ec1..9aefeabf 100644 --- a/KernelLand/Kernel/threads.c +++ b/KernelLand/Kernel/threads.c @@ -493,7 +493,13 @@ tTID Threads_WaitTID(int TID, int *Status) ret = dead_thread->TID; // - Mark as dead (as opposed to undead) - ASSERTC(dead_thread->Status, ==, THREAD_STAT_ZOMBIE); + if( dead_thread->Status != THREAD_STAT_ZOMBIE ) { + Log_Error("Thread", "Thread %p(%i %s) is not ZOMBIE, instead %s", + dead_thread, dead_thread->TID, dead_thread->ThreadName, + (dead_thread->Status < ciTHREAD_STAT_COUNT ? casTHREAD_STAT[dead_thread->Status] : "?") + ); + ASSERTC(dead_thread->Status, ==, THREAD_STAT_ZOMBIE); + } dead_thread->Status = THREAD_STAT_DEAD; // - Set return status if(Status) @@ -503,7 +509,7 @@ tTID Threads_WaitTID(int TID, int *Status) } else { - Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child"); + Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Woken with no child"); } return ret; } @@ -627,17 +633,13 @@ void Threads_Exit(int TID, int Status) */ void Threads_Kill(tThread *Thread, int Status) { - tMsg *msg; int isCurThread = Thread == Proc_GetCurThread(); // TODO: Disown all children? #if 1 { - tThread *child; // TODO: I should keep a .Children list - for(child = gAllThreads; - child; - child = child->GlobalNext) + for(tThread* child = gAllThreads; child; child = child->GlobalNext) { if(child->Parent == Thread) child->Parent = &gThreadZero; @@ -653,7 +655,7 @@ void Threads_Kill(tThread *Thread, int Status) // Clear Message Queue while( Thread->Messages ) { - msg = Thread->Messages->Next; + tMsg *msg = Thread->Messages->Next; free( Thread->Messages ); Thread->Messages = msg; } @@ -701,8 +703,8 @@ void Threads_Kill(tThread *Thread, int Status) if( !Threads_int_DelFromQueue( &gSleepingThreads, Thread ) ) { Log_Warning("Threads", - "Threads_Kill - Thread %p(%i,%s) marked as sleeping, but not on list", - Thread, Thread->TID, Thread->ThreadName + "Threads_Kill - Thread "PRIthread_fmt" marked as sleeping, but not on list", + PRIthread_args(Thread) ); } break; @@ -724,8 +726,6 @@ void Threads_Kill(tThread *Thread, int Status) // Save exit status Thread->RetStatus = Status; - SHORTREL( &Thread->IsLocked ); - Thread->Status = THREAD_STAT_ZOMBIE; SHORTREL( &glThreadListLock ); // TODO: It's possible that we could be timer-preempted here, should disable that... somehow @@ -735,7 +735,10 @@ void Threads_Kill(tThread *Thread, int Status) Threads_PostEvent( Thread->Parent, THREAD_EVENT_DEADCHILD ); // Process cleanup happens on reaping - Log("Thread %i went *hurk* (%i)", Thread->TID, Status); + Log("Thread "PRIthread_fmt" went *hurk* (%i) (isCurThread=%B)", PRIthread_args(Thread), Status, isCurThread); + //Log("Thread status = %i %s", Thread->Status, casTHREAD_STAT[Thread->Status]); + + SHORTREL( &Thread->IsLocked ); // And, reschedule if(isCurThread) -- 2.20.1 From db55040ba8814edf681d4ccc12ad8955d8aa404a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 12:30:31 +0800 Subject: [PATCH 13/16] Usermode/utests - Fix DNS utest, update libc utests to new format (no more EXP files) --- Usermode/Libraries/.gitignore | 1 + Usermode/Libraries/Makefile.tpl | 9 +- .../Libraries/_utest_include/utest_common.h | 23 ++ Usermode/Libraries/libc.so_src/TEST_printf.c | 50 ++-- Usermode/Libraries/libc.so_src/TEST_string.c | 65 ++-- Usermode/Libraries/libc.so_src/TEST_strtoi.c | 12 +- Usermode/Libraries/libnet.so_src/Makefile | 4 +- .../{TEST_dns.c => TEST_dns_proto.c} | 60 +++- Usermode/Libraries/libnet.so_src/dns.c | 264 +--------------- Usermode/Libraries/libnet.so_src/dns_proto.c | 281 ++++++++++++++++++ .../Libraries/libnet.so_src/include/dns.h | 3 +- .../Libraries/libnet.so_src/include/dns_int.h | 14 + 12 files changed, 449 insertions(+), 337 deletions(-) create mode 100644 Usermode/Libraries/_utest_include/utest_common.h rename Usermode/Libraries/libnet.so_src/{TEST_dns.c => TEST_dns_proto.c} (62%) create mode 100644 Usermode/Libraries/libnet.so_src/dns_proto.c create mode 100644 Usermode/Libraries/libnet.so_src/include/dns_int.h diff --git a/Usermode/Libraries/.gitignore b/Usermode/Libraries/.gitignore index 7836cbd6..b6e2b7c6 100644 --- a/Usermode/Libraries/.gitignore +++ b/Usermode/Libraries/.gitignore @@ -1,2 +1,3 @@ acess.ld TEST_* +!TEST_*.c diff --git a/Usermode/Libraries/Makefile.tpl b/Usermode/Libraries/Makefile.tpl index de263f52..8706a0a8 100644 --- a/Usermode/Libraries/Makefile.tpl +++ b/Usermode/Libraries/Makefile.tpl @@ -63,9 +63,12 @@ _libs: $(HEADERS) utest: utest-build utest-run -utest-build: $(UTESTS:%=TEST_%) +utest-build: _ $(UTESTS:%=TEST_%) -utest-run: $(UTESTS:%=runtest-%) +utest-run: _ $(UTESTS:%=runtest-%) + +_: + @true $(UTESTS:%=runtest-%): runtest-%: TEST_% @echo --- [TEST] $* @@ -132,7 +135,7 @@ $(OUTPUTDIR)Libs/%: obj-native/%.no: %.c @mkdir -p $(dir $@) @echo [CC Native] -o $@ - @$(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF $@.dep '-D_SysDebug(f,v...)=fprintf(stderr,"DEBUG "f"\n",##v)' -include stdio.h + @$(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF $@.dep '-D_SysDebug(f,v...)=fprintf(stderr,"DEBUG "f"\n",##v)' -include stdio.h -I $(ACESSDIR)/Usermode/Libraries/_utest_include/ TEST_%: obj-native/TEST_%.no obj-native/%.no @echo [CC Native] -o $@ diff --git a/Usermode/Libraries/_utest_include/utest_common.h b/Usermode/Libraries/_utest_include/utest_common.h new file mode 100644 index 00000000..0b96586f --- /dev/null +++ b/Usermode/Libraries/_utest_include/utest_common.h @@ -0,0 +1,23 @@ +#ifndef _UTEST_COMMON_H_ +#define _UTEST_COMMON_H_ + +#include + +// --- Test assertions +#define TEST_REL_(_ty, _fmt, exp, rel, have) do { \ + _ty a = (exp);\ + _ty b = (have);\ + if( !(a rel b) ) { \ + fprintf(stderr, "TEST_REL_INT("#exp" {%"_fmt"} "#rel" "#have" {%"_fmt"}) FAILED\n", \ + a, b); \ + return 1; \ + } \ +} while(0) +#define TEST_REL_INT(exp, rel, have) TEST_REL_(int, "i", exp, rel, have) +#define TEST_REL_PTR(exp, rel, have) TEST_REL_(const void*, "p", exp, rel, have) + +// -- Header hooks (allowing inclusion of general headers) +#define SYSCALL(rt, name) rt name() { fprintf(stderr, "BUG: Calling syscall '"#name"' in unit test\n"); exit(2); } + +#endif + diff --git a/Usermode/Libraries/libc.so_src/TEST_printf.c b/Usermode/Libraries/libc.so_src/TEST_printf.c index 43766944..c1cdd797 100644 --- a/Usermode/Libraries/libc.so_src/TEST_printf.c +++ b/Usermode/Libraries/libc.so_src/TEST_printf.c @@ -6,32 +6,40 @@ * - Tests for printf.c */ #include +#include +#include -#define TST(_name, fmt, val) \ - printf(_name" %"fmt" '"#val"': '"fmt"'\n", val) +#define TST(_name, exp, fmt, val...) do { \ + char buf[64]; \ + snprintf(buf, sizeof(buf), fmt, ##val); \ + if( strcmp(buf, exp) != 0 ) { \ + fprintf(stderr, "FAIL: exp '%s' != got '%s'\n", exp, buf);\ + exit(1); \ + } \ +} while(0) int main(int argc, char *argv[]) { - printf("Hello World!\n"); - TST("String", "%s", "teststring"); - TST("String", "%.5s", "teststring"); - TST("String", "%10.5s", "teststring"); - TST("String", "%-10.5s", "teststring"); + TST("None", "Hello World!\n", "Hello World!\n"); + TST("String", "teststring", "%s", "teststring"); + TST("String", "tests", "%.5s", "teststring"); + TST("String", " tests", "%10.5s", "teststring"); + TST("String", "tests ", "%-10.5s", "teststring"); - TST("Integer", "%i", 1234); - TST("Integer", "%d", 1234); - TST("Integer", "%u", 1234); + TST("Integer", "1234", "%i", 1234); + TST("Integer", "1234", "%d", 1234); + TST("Integer", "1234", "%u", 1234); - TST("Float", "%f", 3.1414926535); - TST("Float", "%f", 10.0); - TST("Float", "%f", -0.0); - TST("Float", "%.10f", 3.1414926535); - TST("Float", "%e", 3.1415926535); - TST("Float", "%g", 3.1415926535); - TST("Float", "%E", 1000000000.00); - TST("Float", "%a", 16.0); - TST("Float", "%a", 1024.0); - TST("Float", "%a", 1023.0); - TST("Float", "%A", 1000000000.00); + TST("Float", "3.141593", "%f", 3.1415926535); + TST("Float", "10.000000", "%f", 10.0); + TST("Float", "-0.000000", "%f", -0.0); + TST("Float", "3.1415926535", "%.10f", 3.1415926535); + TST("Float", "3.141593e+00", "%e", 3.1415926535); + TST("Float", "3.14159", "%g", 3.1415926535); + TST("Float", "1.000000E+09", "%E", 1000000000.00); + TST("Float", "0x1p+4", "%a", 16.0); + TST("Float", "0x1p+10", "%a", 1024.0); + TST("Float", "0x1.ff8p+9", "%a", 1023.0); + TST("Float", "0X1.DCD65P+29", "%A", 1000000000.00); return 0; } diff --git a/Usermode/Libraries/libc.so_src/TEST_string.c b/Usermode/Libraries/libc.so_src/TEST_string.c index 4ecca307..eb940c7e 100644 --- a/Usermode/Libraries/libc.so_src/TEST_string.c +++ b/Usermode/Libraries/libc.so_src/TEST_string.c @@ -2,50 +2,55 @@ */ #include #include - -#define ASSERT(cnd) printf("ASSERT: "#cnd" == %s\n", ((cnd) ? "pass" : "FAIL")) +#include int main() { - ASSERT(strcmp("hello", "world") < 0); - ASSERT(strcmp("hello", "hello") == 0); - ASSERT(strcmp("wello", "hello") > 0); - ASSERT(strcmp("\xff", "\1") > 0); - ASSERT(strcmp("\1", "\xff") < 0); - ASSERT(strcmp("Hello", "hello") < 0); + TEST_REL_INT(0, > , strcmp("hello", "world")); + TEST_REL_INT(0, ==, strcmp("hello", "hello")); + TEST_REL_INT(0, < , strcmp("wello", "hello")); + TEST_REL_INT(0, < , strcmp("\xff", "\1")); + TEST_REL_INT(0, > , strcmp("\1", "\xff")); + TEST_REL_INT(0, > , strcmp("Hello", "hello")); - ASSERT(strncmp("hello world", "hello", 5) == 0); + TEST_REL_INT(0, ==, strncmp("hello world", "hello", 5)); - ASSERT(strcasecmp("hello", "world") < 0); - ASSERT(strcasecmp("hello", "hello") == 0); - ASSERT(strcasecmp("wello", "hello") > 0); - ASSERT(strcasecmp("\xff", "\1") > 0); - ASSERT(strcasecmp("\1", "\xff") < 0); - ASSERT(strcasecmp("Hello", "hello") == 0); - ASSERT(strcasecmp("Hello", "Hello") == 0); - ASSERT(strcasecmp("hellO", "Hello") == 0); + TEST_REL_INT(0, > , strcasecmp("hello", "world")); + TEST_REL_INT(0, ==, strcasecmp("hello", "hello")); + TEST_REL_INT(0, < , strcasecmp("wello", "hello")); + TEST_REL_INT(0, < , strcasecmp("\xff", "\1")); + TEST_REL_INT(0, > , strcasecmp("\1", "\xff")); + TEST_REL_INT(0, ==, strcasecmp("Hello", "hello")); + TEST_REL_INT(0, ==, strcasecmp("Hello", "Hello")); + TEST_REL_INT(0, ==, strcasecmp("hellO", "Hello")); char buf[13]; memset(buf, 127, sizeof(buf)); - ASSERT(buf[0] == 127); ASSERT(buf[4] == 127); + TEST_REL_INT(127, ==, buf[0]); + TEST_REL_INT(127, ==, buf[4]); strncpy(buf, "hello", 4); - ASSERT(buf[3] == 'l'); ASSERT(buf[4] == 127); + TEST_REL_INT('l', ==, buf[3]); + TEST_REL_INT(127, ==, buf[4]); strncpy(buf, "hello", 8); - ASSERT(buf[4] == 'o'); ASSERT(buf[5] == '\0'); ASSERT(buf[7] == '\0'); ASSERT(buf[8] == 127); + TEST_REL_INT('o', ==, buf[4]); + TEST_REL_INT('\0', ==, buf[5]); + TEST_REL_INT('\0', ==, buf[7]); + TEST_REL_INT(127, ==, buf[8]); memset(buf, 0, 13); - ASSERT(buf[0] == 0); ASSERT(buf[12] == 0); + TEST_REL_INT(0, ==, buf[0]); + TEST_REL_INT(0, ==, buf[12]); - ASSERT(memchr("\xffhello", 'x', 6) == NULL); + TEST_REL_PTR(NULL, ==, memchr("\xffhello", 'x', 6)); const char *teststr_foo = "foo"; - ASSERT(strchr(teststr_foo, 'f') == teststr_foo+0); - ASSERT(strchr(teststr_foo, 'o') == teststr_foo+1); - ASSERT(strchr(teststr_foo, '\0') == teststr_foo+3); - ASSERT(strchr(teststr_foo, 'X') == NULL); - ASSERT(strrchr(teststr_foo, 'f') == teststr_foo+0); - ASSERT(strrchr(teststr_foo, 'o') == teststr_foo+2); - ASSERT(strrchr(teststr_foo, '\0') == teststr_foo+3); - ASSERT(strrchr(teststr_foo, 'X') == NULL); + TEST_REL_PTR(teststr_foo+0, ==, strchr(teststr_foo, 'f')); + TEST_REL_PTR(teststr_foo+1, ==, strchr(teststr_foo, 'o')); + TEST_REL_PTR(teststr_foo+3, ==, strchr(teststr_foo, '\0')); + TEST_REL_PTR(NULL, ==, strchr(teststr_foo, 'X')); + TEST_REL_PTR(teststr_foo+0, ==, strrchr(teststr_foo, 'f')); + TEST_REL_PTR(teststr_foo+2, ==, strrchr(teststr_foo, 'o')); + TEST_REL_PTR(teststr_foo+3, ==, strrchr(teststr_foo, '\0')); + TEST_REL_PTR(NULL, ==, strrchr(teststr_foo, 'X')); } diff --git a/Usermode/Libraries/libc.so_src/TEST_strtoi.c b/Usermode/Libraries/libc.so_src/TEST_strtoi.c index e0658087..cf2d2698 100644 --- a/Usermode/Libraries/libc.so_src/TEST_strtoi.c +++ b/Usermode/Libraries/libc.so_src/TEST_strtoi.c @@ -18,14 +18,20 @@ char *end;\ errno = 0;\ t ret = strto##class(in, &end, base); \ - if( ret != exp ) \ + if( ret != exp ) { \ fprintf(stderr, "FAIL strto"#class"('%s') != "#exp" (act "fmt")\n", in, ret);\ - if( end != in+ofs ) \ + exit(1); \ + } \ + if( end != in+ofs ) { \ fprintf(stderr, "FAIL strto"#class"('%s') returned wrong end: %p (+%zi) instead of %p (+%zi)\n",\ in,end,end-in,in+ofs,(size_t)ofs);\ - if( exp_errno != errno ) \ + exit(1); \ + } \ + if( exp_errno != errno ) { \ fprintf(stderr, "FAIL strto"#class"('%s') returned wrong errno, exp '%s', got '%s'\n",\ in, strerror(exp_errno), strerror(errno));\ + exit(1); \ + } \ }while(0) #define PRIMEBUF(fmt, val) buf_len = snprintf(buf, sizeof(buf), fmt, val) diff --git a/Usermode/Libraries/libnet.so_src/Makefile b/Usermode/Libraries/libnet.so_src/Makefile index 10d5b962..ef733703 100644 --- a/Usermode/Libraries/libnet.so_src/Makefile +++ b/Usermode/Libraries/libnet.so_src/Makefile @@ -7,9 +7,9 @@ CFLAGS += -Wall LDFLAGS += -lc -soname libnet.so OBJ = main.o address.o socket.o -OBJ += hostnames.o dns.o +OBJ += hostnames.o dns.o dns_proto.o BIN = libnet.so -UTESTS = dns +UTESTS = dns_prot include ../Makefile.tpl diff --git a/Usermode/Libraries/libnet.so_src/TEST_dns.c b/Usermode/Libraries/libnet.so_src/TEST_dns_proto.c similarity index 62% rename from Usermode/Libraries/libnet.so_src/TEST_dns.c rename to Usermode/Libraries/libnet.so_src/TEST_dns_proto.c index 26b36bf5..49ba0232 100644 --- a/Usermode/Libraries/libnet.so_src/TEST_dns.c +++ b/Usermode/Libraries/libnet.so_src/TEST_dns_proto.c @@ -1,43 +1,70 @@ /* */ -#include "include/dns.h" +#include +#include "include/dns_int.h" #include #include #include -extern int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); - // Complex response from "Q ssh.ucc.asn.au A IN" const uint8_t test_packet_1[] = { 0xac, 0x00, 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x03, 0x73, 0x73, 0x68, 0x03, 0x75, 0x63, 0x63, 0x03, 0x61, 0x73, 0x6e, 0x02, 0x61, 0x75, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x77, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x78, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x79, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x61, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x7a, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x62, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x75, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x76, 0xc0, 0x18, 0xc0, 0x2c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc0, 0x05, 0xc0, 0x3c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc2, 0x05, 0xc0, 0x4c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc4, 0x05, 0xc0, 0x5c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x3a, 0x41, 0xfe, 0x49, 0xc0, 0x6c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc6, 0x05, 0xc0, 0x7c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x3a, 0x41, 0xfd, 0x49, 0xc0, 0x8c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0xd3, 0x1d, 0x85, 0x20, 0xc0, 0x9c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0xca, 0x0c, 0x1f, 0x8d, }; +const uint8_t test_packet_2[] ={ + 0xac,0x00,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x03,0x73,0x73,0x68,0x03,0x75,0x63,0x63,0x03,0x61,0x73,0x6e,0x02,0x61,0x75,0x00,0x00,0x01,0x00,0x01,0xc0,0x0c,0x00,0x01,0x00,0x01,0x00,0x00,0x0e,0x10,0x00,0x04,0x82,0x5f,0x0d,0x0b +}; -#define TEST_REL_INT(exp, rel, have) do { \ - int a = (exp);\ - int b = (have);\ - if( !(a rel b) ) { \ - fprintf(stderr, "TEST_REL_INT("#exp" "#rel" "#exp") FAILED l=%i r=%i", \ - a, b); \ - return 1; \ - } \ -} while(0) - int test_response_parse_1_cb(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) { int* stagep = info; - switch( *stagep ) + int curstage = *stagep; + *stagep = -1; + switch( curstage ) { case 0: - TEST_REL_INT(0, ==, strcmp(name, "au.")); + TEST_REL_INT(0, ==, strcmp(name, "w.au.")); + break; + case 1: + TEST_REL_INT(0, ==, strcmp(name, "x.au.")); break; } - (*stagep) += 1; + *stagep = curstage + 1; return 0; } int test_response_parse_1(void) { int stage = 0; TEST_REL_INT(0, ==, DNS_int_ParseResponse(test_packet_1, sizeof(test_packet_1), &stage, test_response_parse_1_cb) ); + TEST_REL_INT(stage, ==, 8); + return 0; +} + +int test_response_parse_2_cb(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) +{ + int* stagep = info; + int curstage = *stagep; + *stagep = -1; + switch( curstage ) + { + case 0: + TEST_REL_INT(0, ==, strcmp(name, "ssh.ucc.asn.au.")); + TEST_REL_INT(TYPE_A, ==, type); + TEST_REL_INT(CLASS_IN, ==, class); + TEST_REL_INT(4, ==, rdlength); + TEST_REL_INT(130, ==, ((uint8_t*)rdata)[0]); + TEST_REL_INT( 95, ==, ((uint8_t*)rdata)[1]); + TEST_REL_INT( 13, ==, ((uint8_t*)rdata)[2]); + TEST_REL_INT( 11, ==, ((uint8_t*)rdata)[3]); + break; + } + *stagep = curstage + 1; + return 0; +} +int test_response_parse_2(void) +{ + int stage = 0; + TEST_REL_INT(0, ==, DNS_int_ParseResponse(test_packet_2, sizeof(test_packet_2), &stage, test_response_parse_2_cb) ); + TEST_REL_INT(stage, ==, 1); return 0; } @@ -48,5 +75,6 @@ int main(void) // - Name Decode // - Response parsing rv |= test_response_parse_1(); + rv |= test_response_parse_2(); return rv; } diff --git a/Usermode/Libraries/libnet.so_src/dns.c b/Usermode/Libraries/libnet.so_src/dns.c index 3bb9c355..9ac9198b 100644 --- a/Usermode/Libraries/libnet.so_src/dns.c +++ b/Usermode/Libraries/libnet.so_src/dns.c @@ -13,40 +13,16 @@ #include // FD_SET #include #include "include/dns.h" +#include "include/dns_int.h" // === PROTOTYPES === //int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info); -int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); -size_t DNS_EncodeName(void *buf, const char *dotted_name); -int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space); -int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p); - -static uint16_t get16(const void *buf); -static uint32_t get32(const void *buf); -static size_t put16(void *buf, uint16_t val); - // === CODE === int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info) { - int namelen = DNS_EncodeName(NULL, name); - assert(namelen < 256); - size_t pos = 0; - char packet[ 512 ]; - assert( (6*2) + (namelen + 2*2) < 512 ); - // - Header - pos += put16(packet + pos, 0xAC00); // Identifier (arbitary) - pos += put16(packet + pos, (0 << 0) | (0 << 1) | (1 << 8) ); // Op : Query, Standard, Recursion - pos += put16(packet + pos, 1); // QDCount - pos += put16(packet + pos, 0); // ANCount - pos += put16(packet + pos, 0); // NSCount - pos += put16(packet + pos, 0); // ARCount - // - Question - pos += DNS_EncodeName(packet + pos, name); - pos += put16(packet + pos, type); // QType - pos += put16(packet + pos, class); // QClass - - assert(pos <= sizeof(packet)); + char packet[512]; + size_t packlen = DNS_int_EncodeQuery(packet, sizeof(packet), name, type, class); // Send and wait for reply // - Lock @@ -102,237 +78,3 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT return DNS_int_ParseResponse(packet, return_len, info, handle_record); } -int DNS_int_ParseResponse(const void* buf, size_t return_len, void *info, handle_record_t* handle_record) -{ - const uint8_t* packet = buf; - char rr_name[256]; - unsigned int id = get16(packet + 0); - if( id != 0xAC00 ) { - _SysDebug("DNS_Query - Packet ID mismatch"); - return 2; - } - unsigned int flags = get16(packet + 2); - unsigned int qd_count = get16(packet + 4); - unsigned int an_count = get16(packet + 6); - unsigned int ns_count = get16(packet + 8); - unsigned int ar_count = get16(packet + 10); - size_t pos = 6*2; - // TODO: Can I safely assert / fail if qd_count is non-zero? - // - Questions, ignored - for( unsigned int i = 0; i < qd_count; i ++ ) { - int rv = DNS_DecodeName(rr_name, packet, pos, return_len); - if( rv < 0 ) { - _SysDebug("DNS_Query - Parse error in QD"); - return 1; - } - pos += rv + 2*2; - } - // - Answers, pass on to handler - for( unsigned int i = 0; i < an_count; i ++ ) - { - enum eTypes type; - enum eClass class; - uint32_t ttl; - size_t rdlength; - int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); - if( rv < 0 ) { - _SysDebug("DNS_Query - Parse error in AN"); - return 1; - } - pos += rv; - - handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); - } - // Authority Records (should all be NS records) - for( unsigned int i = 0; i < ns_count; i ++ ) - { - size_t rdlength; - int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, NULL, NULL, NULL, &rdlength); - if( rv < 0 ) { - _SysDebug("DNS_Query - Parse error in NS"); - return 1; - } - pos += rv; - } - // - Additional records, pass to handler - for( unsigned int i = 0; i < ar_count; i ++ ) - { - enum eTypes type; - enum eClass class; - uint32_t ttl; - size_t rdlength; - int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); - if( rv < 0 ) { - _SysDebug("DNS_Query - Parse error in AR"); - return 1; - } - pos += rv; - - handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); - } - - return 0; -} - -/// Encode a dotted name as a DNS name -size_t DNS_EncodeName(void *buf, const char *dotted_name) -{ - size_t ret = 0; - const char *str = dotted_name; - uint8_t *buf8 = buf; - while( *str ) - { - const char *next = strchr(str, '.'); - size_t seg_len = (next ? next - str : strlen(str)); - if( seg_len > 63 ) { - // Oops, too long (truncate) - seg_len = 63; - } - if( seg_len == 0 && next != NULL ) { - // '..' encountered, invalid (skip) - str = next+1; - continue ; - } - - if( buf8 ) - { - buf8[ret] = seg_len; - memcpy(buf8+ret+1, str, seg_len); - } - ret += 1 + seg_len; - - if( next == NULL ) { - // No trailing '.', assume it's there? Yes, need to be NUL terminated - if(buf8) buf8[ret] = 0; - ret ++; - break; - } - else { - str = next + 1; - } - } - return ret; -} - -// Decode a name (including trailing . for root) -int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space) -{ - int consumed = 0; - int out_pos = 0; - const uint8_t *buf8 = (const uint8_t*)buf + ofs; - for( ;; ) - { - if( ofs + consumed + 1 > space ) { - _SysDebug("DNS_DecodeName - Len byte OOR space=%i", space); - return -1; - } - uint8_t seg_len = *buf8; - buf8 ++; - consumed ++; - // Done - if( seg_len == 0 ) - break; - if( (seg_len & 0xC0) == 0xC0 ) - { - // Backreference, the rest of the name is a backref - char tmp[256]; - int ref_ofs = get16(buf8 - 1) & 0x3FFF; - consumed += 1, buf8 += 1; // Only one, previous inc still applies - _SysDebug("DNS_DecodeName - Nested at %i", ref_ofs); - if( DNS_DecodeName(tmp, buf, ref_ofs, space) < 0 ) - return -1; - memcpy(dotted_name+out_pos, tmp, strlen(tmp)); - out_pos += strlen(tmp); - break; - } - // Protocol violation (segment too long) - if( seg_len >= 64 ) { - _SysDebug("DNS_DecodeName - Seg too long %i", seg_len); - return -1; - } - // Protocol violation (overflowed end of buffer) - if( ofs + consumed + seg_len > space ) { - _SysDebug("DNS_DecodeName - Seg OOR %i+%i>%i", consumed, seg_len, space); - return -1; - } - // Protocol violation (name was too long) - if( out_pos + seg_len + 1 > 255 ) { - _SysDebug("DNS_DecodeName - Dotted name too long %i+%i+1 > %i", - out_pos, seg_len, 255); - return -1; - } - - _SysDebug("DNS_DecodeName : Seg %i '%.*s'", seg_len, seg_len, buf8); - - // Read segment - memcpy(dotted_name + out_pos, buf8, seg_len); - buf8 += seg_len; - consumed += seg_len; - out_pos += seg_len; - - // Place '.' - dotted_name[out_pos] = '.'; - out_pos ++; - } - dotted_name[out_pos] = '\0'; - _SysDebug("DNS_DecodeName - '%s', consumed = %i", dotted_name, consumed); - return consumed; -} - -// Parse a Resource Record -int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p) -{ - const uint8_t *buf8 = buf; - size_t consumed = 0; - - // 1. Name - int rv = DNS_DecodeName(name_p, buf, ofs, space); - if(rv < 0) return -1; - - ofs += rv, consumed += rv; - - if( type_p ) - *type_p = get16(buf8 + ofs); - ofs += 2, consumed += 2; - - if( class_p ) - *class_p = get16(buf8 + ofs); - ofs += 2, consumed += 2; - - if( ttl_p ) - *ttl_p = get32(buf + ofs); - ofs += 4, consumed += 4; - - size_t rdlength = get16(buf + ofs); - if( rdlength_p ) - *rdlength_p = rdlength; - ofs += 2, consumed += 2; - - _SysDebug("DNS_int_ParseRR - name='%s', rdlength=%i", name_p, rdlength); - - return consumed + rdlength; -} - -static uint16_t get16(const void *buf) { - const uint8_t* buf8 = buf; - uint16_t rv = 0; - rv |= (uint16_t)buf8[0] << 8; - rv |= (uint16_t)buf8[1] << 0; - return rv; -} -static uint32_t get32(const void *buf) { - const uint8_t* buf8 = buf; - uint32_t rv = 0; - rv |= (uint32_t)buf8[0] << 24; - rv |= (uint32_t)buf8[1] << 16; - rv |= (uint32_t)buf8[2] << 8; - rv |= (uint32_t)buf8[3] << 0; - return rv; -} -static size_t put16(void *buf, uint16_t val) { - uint8_t* buf8 = buf; - buf8[0] = val >> 8; - buf8[1] = val & 0xFF; - return 2; -} - diff --git a/Usermode/Libraries/libnet.so_src/dns_proto.c b/Usermode/Libraries/libnet.so_src/dns_proto.c new file mode 100644 index 00000000..ce3cfb3e --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/dns_proto.c @@ -0,0 +1,281 @@ +/* + */ + +#include "include/dns.h" +#include "include/dns_int.h" +#include +#include +#include + +// === PROTOTYPES === +extern int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p); + +static uint16_t get16(const void *buf); +static uint32_t get32(const void *buf); +static size_t put16(void *buf, uint16_t val); + +// === CODE === +size_t DNS_int_EncodeQuery(void *buf, size_t bufsize, const char *name, enum eTypes type, enum eClass class) +{ + int namelen = DNS_EncodeName(NULL, name); + if( namelen >= 256 ) { + _SysDebug("DNS_int_EncodeQuery - ERROR: Name encoded to >= 256 bytes"); + return 0; + } + size_t pos = 0; + uint8_t *packet = buf; + if( (6*2) + (namelen + 2*2) > bufsize ) { + _SysDebug("DNS_int_EncodeQuery - ERROR: Passed buffer too small"); + return 0; + } + // - Header + pos += put16(packet + pos, 0xAC00); // Identifier (arbitary) + pos += put16(packet + pos, (0 << 0) | (0 << 1) | (1 << 8) ); // Op : Query, Standard, Recursion + pos += put16(packet + pos, 1); // QDCount + pos += put16(packet + pos, 0); // ANCount + pos += put16(packet + pos, 0); // NSCount + pos += put16(packet + pos, 0); // ARCount + // - Question + pos += DNS_EncodeName(packet + pos, name); + pos += put16(packet + pos, type); // QType + pos += put16(packet + pos, class); // QClass + + assert(pos <= bufsize); + return pos; +} + +int DNS_int_ParseResponse(const void* buf, size_t return_len, void *info, handle_record_t* handle_record) +{ + const uint8_t* packet = buf; + char rr_name[256]; + unsigned int id = get16(packet + 0); + if( id != 0xAC00 ) { + _SysDebug("DNS_Query - Packet ID mismatch"); + return 2; + } + unsigned int flags = get16(packet + 2); + unsigned int qd_count = get16(packet + 4); + unsigned int an_count = get16(packet + 6); + unsigned int ns_count = get16(packet + 8); + unsigned int ar_count = get16(packet + 10); + size_t pos = 6*2; + // TODO: Can I safely assert / fail if qd_count is non-zero? + // - Questions, ignored + for( unsigned int i = 0; i < qd_count; i ++ ) { + int rv = DNS_DecodeName(rr_name, packet, pos, return_len); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in QD"); + return 1; + } + pos += rv + 2*2; + } + // - Answers, pass on to handler + for( unsigned int i = 0; i < an_count; i ++ ) + { + enum eTypes type; + enum eClass class; + uint32_t ttl; + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in AN"); + return 1; + } + pos += rv; + + if( handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength) ) + return 0; + } + // Authority Records (should all be NS records) + for( unsigned int i = 0; i < ns_count; i ++ ) + { + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, NULL, NULL, NULL, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in NS"); + return 1; + } + pos += rv; + } + // - Additional records, pass to handler + for( unsigned int i = 0; i < ar_count; i ++ ) + { + enum eTypes type; + enum eClass class; + uint32_t ttl; + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in AR"); + return 1; + } + pos += rv; + + if( handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength) ) + return 0; + } + + return 0; +} + +/// Encode a dotted name as a DNS name +size_t DNS_EncodeName(void *buf, const char *dotted_name) +{ + size_t ret = 0; + const char *str = dotted_name; + uint8_t *buf8 = buf; + while( *str ) + { + const char *next = strchr(str, '.'); + size_t seg_len = (next ? next - str : strlen(str)); + if( seg_len > 63 ) { + // Oops, too long (truncate) + seg_len = 63; + } + if( seg_len == 0 && next != NULL ) { + // '..' encountered, invalid (skip) + str = next+1; + continue ; + } + + if( buf8 ) + { + buf8[ret] = seg_len; + memcpy(buf8+ret+1, str, seg_len); + } + ret += 1 + seg_len; + + if( next == NULL ) { + // No trailing '.', assume it's there? Yes, need to be NUL terminated + if(buf8) buf8[ret] = 0; + ret ++; + break; + } + else { + str = next + 1; + } + } + return ret; +} + +// Decode a name (including trailing . for root) +int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space) +{ + int consumed = 0; + int out_pos = 0; + const uint8_t *buf8 = (const uint8_t*)buf + ofs; + for( ;; ) + { + if( ofs + consumed + 1 > space ) { + _SysDebug("DNS_DecodeName - Len byte OOR space=%zi", space); + return -1; + } + uint8_t seg_len = *buf8; + buf8 ++; + consumed ++; + // Done + if( seg_len == 0 ) + break; + if( (seg_len & 0xC0) == 0xC0 ) + { + // Backreference, the rest of the name is a backref + char tmp[256]; + int ref_ofs = get16(buf8 - 1) & 0x3FFF; + consumed += 1, buf8 += 1; // Only one, previous inc still applies + //_SysDebug("DNS_DecodeName - Nested at %i", ref_ofs); + if( DNS_DecodeName(tmp, buf, ref_ofs, space) < 0 ) + return -1; + memcpy(dotted_name+out_pos, tmp, strlen(tmp)); + out_pos += strlen(tmp); + break; + } + // Protocol violation (segment too long) + if( seg_len >= 64 ) { + _SysDebug("DNS_DecodeName - Seg too long %i", seg_len); + return -1; + } + // Protocol violation (overflowed end of buffer) + if( ofs + consumed + seg_len > space ) { + _SysDebug("DNS_DecodeName - Seg OOR %i+%i>%zi", consumed, seg_len, space); + return -1; + } + // Protocol violation (name was too long) + if( out_pos + seg_len + 1 > 255 ) { + _SysDebug("DNS_DecodeName - Dotted name too long %i+%i+1 > %i", + out_pos, seg_len, 255); + return -1; + } + + //_SysDebug("DNS_DecodeName : Seg %i '%.*s'", seg_len, seg_len, buf8); + + // Read segment + memcpy(dotted_name + out_pos, buf8, seg_len); + buf8 += seg_len; + consumed += seg_len; + out_pos += seg_len; + + // Place '.' + dotted_name[out_pos] = '.'; + out_pos ++; + } + dotted_name[out_pos] = '\0'; + //_SysDebug("DNS_DecodeName - '%s', consumed = %i", dotted_name, consumed); + return consumed; +} + +// Parse a Resource Record +int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p) +{ + const uint8_t *buf8 = buf; + size_t consumed = 0; + + // 1. Name + int rv = DNS_DecodeName(name_p, buf, ofs, space); + if(rv < 0) return -1; + + ofs += rv, consumed += rv; + + if( type_p ) + *type_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; + + if( class_p ) + *class_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; + + if( ttl_p ) + *ttl_p = get32(buf + ofs); + ofs += 4, consumed += 4; + + size_t rdlength = get16(buf + ofs); + if( rdlength_p ) + *rdlength_p = rdlength; + ofs += 2, consumed += 2; + + _SysDebug("DNS_int_ParseRR - name='%s', rdlength=%zi", name_p, rdlength); + + return consumed + rdlength; +} + +static uint16_t get16(const void *buf) { + const uint8_t* buf8 = buf; + uint16_t rv = 0; + rv |= (uint16_t)buf8[0] << 8; + rv |= (uint16_t)buf8[1] << 0; + return rv; +} +static uint32_t get32(const void *buf) { + const uint8_t* buf8 = buf; + uint32_t rv = 0; + rv |= (uint32_t)buf8[0] << 24; + rv |= (uint32_t)buf8[1] << 16; + rv |= (uint32_t)buf8[2] << 8; + rv |= (uint32_t)buf8[3] << 0; + return rv; +} +static size_t put16(void *buf, uint16_t val) { + uint8_t* buf8 = buf; + buf8[0] = val >> 8; + buf8[1] = val & 0xFF; + return 2; +} diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h index dc7a58b4..61daeacd 100644 --- a/Usermode/Libraries/libnet.so_src/include/dns.h +++ b/Usermode/Libraries/libnet.so_src/include/dns.h @@ -39,8 +39,9 @@ enum eClass * \param class Record class (may not be equal to requested) * \param rdlength Length of data pointed to by 'rdata' * \param rdata Record data + * \return Non-zero terminates parsing */ -typedef void handle_record_t(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); +typedef int handle_record_t(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info); diff --git a/Usermode/Libraries/libnet.so_src/include/dns_int.h b/Usermode/Libraries/libnet.so_src/include/dns_int.h new file mode 100644 index 00000000..0e20ea10 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/include/dns_int.h @@ -0,0 +1,14 @@ +/* + */ +#ifndef _DNS_INT_H_ +#define _DNS_INT_H_ + +#include "dns.h" + +extern size_t DNS_int_EncodeQuery(void *buf, size_t bufsize, const char *name, enum eTypes type, enum eClass class); +extern int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); + +extern size_t DNS_EncodeName(void *buf, const char *dotted_name); +extern int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space); +#endif + -- 2.20.1 From 6a28fd66345b484f9dfa5dba869888becdaf7112 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 12:53:24 +0800 Subject: [PATCH 14/16] Usermode/libnet - Fix compile errors (silly me) --- Usermode/Libraries/libnet.so_src/dns.c | 8 ++++++-- Usermode/Libraries/libnet.so_src/hostnames.c | 11 ++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Usermode/Libraries/libnet.so_src/dns.c b/Usermode/Libraries/libnet.so_src/dns.c index 9ac9198b..26bf99b1 100644 --- a/Usermode/Libraries/libnet.so_src/dns.c +++ b/Usermode/Libraries/libnet.so_src/dns.c @@ -23,6 +23,10 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT { char packet[512]; size_t packlen = DNS_int_EncodeQuery(packet, sizeof(packet), name, type, class); + if( packlen == 0 ) { + _SysDebug("DNS_Query - Serialising packet failed"); + return 2; + } // Send and wait for reply // - Lock @@ -35,8 +39,8 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT // TODO: Correctly report this failure with a useful error code return 1; } - int rv = Net_UDP_SendTo(sock, 53, ServerAType, ServerAddr, pos, packet); - if( rv != pos ) { + int rv = Net_UDP_SendTo(sock, 53, ServerAType, ServerAddr, packlen, packet); + if( rv != packlen ) { _SysDebug("DNS_Query - Write failed"); // TODO: Error reporting _SysClose(sock); diff --git a/Usermode/Libraries/libnet.so_src/hostnames.c b/Usermode/Libraries/libnet.so_src/hostnames.c index c3c96268..99aa328b 100644 --- a/Usermode/Libraries/libnet.so_src/hostnames.c +++ b/Usermode/Libraries/libnet.so_src/hostnames.c @@ -43,7 +43,7 @@ struct sDNSCallbackInfo // === PROTOTYPES === int int_lookupany_callback(void *info_v, int AddrType, const void *Addr); -void int_DNS_callback(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); + int int_DNS_callback(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); // === GLOBALS === int giNumDNSServers; @@ -127,22 +127,22 @@ int Net_Lookup_Addrs(const char *Name, void *cb_info, tNet_LookupAddrs_Callback return 1; } -void int_DNS_callback(void *info_v, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) +int int_DNS_callback(void *info_v, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) { struct sDNSCallbackInfo *info = info_v; _SysDebug("int_DNS_callback(name='%s', type=%i, class=%i)", name, type, class); // Check type matches (if pattern was provided) if( info->desired_type != QTYPE_STAR && type != info->desired_type ) - return ; + return 0; if( info->desired_class != QCLASS_STAR && class != info->desired_class ) - return ; + return 0; switch( type ) { case TYPE_A: if( rdlength != 4 ) - return ; + return 0; info->callback( info->cb_info, 4, rdata ); break; //case TYPE_AAAA: @@ -155,6 +155,7 @@ void int_DNS_callback(void *info_v, const char *name, enum eTypes type, enum eCl break; } info->got_value = true; + return 0; } int Net_Lookup_Name(int AddrType, const void *Addr, char *Dest[256]) -- 2.20.1 From 86b0974b33759726b99f8940900a88e395247460 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 18 Feb 2015 14:21:05 +0800 Subject: [PATCH 15/16] misc - Cleaning up warnings that occur on travis --- KernelLand/Kernel/include/vfs_ext.h | 4 ++++ KernelLand/Kernel/vfs/acls.c | 17 ++++++++--------- Tools/NetTest_Runner/test_tcp.c | 6 +++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/KernelLand/Kernel/include/vfs_ext.h b/KernelLand/Kernel/include/vfs_ext.h index 42d98654..73d82ce5 100644 --- a/KernelLand/Kernel/include/vfs_ext.h +++ b/KernelLand/Kernel/include/vfs_ext.h @@ -70,6 +70,10 @@ enum eVFS_SeekDirs * \} */ +#define VFS_ACLENT_ALL 0x7FFFFFFF +#define VFS_GROUP_ANY {1, VFS_ACLENT_ALL} //!< Rules for all users +#define VFS_USER_NOBODY {0, VFS_ACLENT_ALL} //!< Rules for nobody + /** * \brief MMap protection flags * \{ diff --git a/KernelLand/Kernel/vfs/acls.c b/KernelLand/Kernel/vfs/acls.c index 7ae50c2f..f8d48608 100644 --- a/KernelLand/Kernel/vfs/acls.c +++ b/KernelLand/Kernel/vfs/acls.c @@ -9,21 +9,20 @@ Uint VFS_int_CheckACLs(tVFS_ACL *ACLs, int Num, int bDeny, Uint Perms, tUID UID, tGID GID); // === GLOBALS === -tVFS_ACL gVFS_ACL_EveryoneRWX = { {1,-1}, {0,VFS_PERM_ALL} }; -tVFS_ACL gVFS_ACL_EveryoneRW = { {1,-1}, {0,VFS_PERM_ALL^VFS_PERM_EXEC} }; -tVFS_ACL gVFS_ACL_EveryoneRX = { {1,-1}, {0,VFS_PERM_READ|VFS_PERM_EXEC} }; -tVFS_ACL gVFS_ACL_EveryoneRO = { {1,-1}, {0,VFS_PERM_READ} }; +tVFS_ACL gVFS_ACL_EveryoneRWX = { VFS_GROUP_ANY, {0,VFS_PERM_ALL} }; +tVFS_ACL gVFS_ACL_EveryoneRW = { VFS_GROUP_ANY, {0,VFS_PERM_ALL^VFS_PERM_EXEC} }; +tVFS_ACL gVFS_ACL_EveryoneRX = { VFS_GROUP_ANY, {0,VFS_PERM_READ|VFS_PERM_EXEC} }; +tVFS_ACL gVFS_ACL_EveryoneRO = { VFS_GROUP_ANY, {0,VFS_PERM_READ} }; // === CODE === Uint VFS_int_CheckACLs(tVFS_ACL *ACLs, int Num, int bDeny, Uint Perms, tUID UID, tGID GID) { - int i; - for(i = 0; i < Num; i ++ ) + for(int i = 0; i < Num; i ++ ) { if(ACLs[i].Perm.Inv) continue; // Ignore ALLOWs // Check if the entry applies to this case - if(ACLs[i].Ent.ID != 0x7FFFFFFF) + if(ACLs[i].Ent.ID != VFS_ACLENT_ALL) { if(!ACLs[i].Ent.Group) { if(ACLs[i].Ent.ID != UID) continue; @@ -95,7 +94,7 @@ int VFS_GetACL(int FD, tVFS_ACL *Dest) // Root can do anything if(Dest->Ent.Group == 0 && Dest->Ent.ID == 0) { Dest->Perm.Inv = 0; - Dest->Perm.Perms = -1; + Dest->Perm.Perms = VFS_PERM_ALL; return 1; } @@ -149,7 +148,7 @@ tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group) if(Mode & 0010) ret[1].Perm.Perms |= VFS_PERM_EXEC; // Global - ret[2].Ent.Group = 1; ret[2].Ent.ID = -1; + ret[2].Ent.Group = 1; ret[2].Ent.ID = VFS_ACLENT_ALL; ret[2].Perm.Inv = 0; ret[2].Perm.Perms = 0; if(Mode & 0004) ret[2].Perm.Perms |= VFS_PERM_READ; if(Mode & 0002) ret[2].Perm.Perms |= VFS_PERM_WRITE; diff --git a/Tools/NetTest_Runner/test_tcp.c b/Tools/NetTest_Runner/test_tcp.c index 42aa2d50..8515f7f5 100644 --- a/Tools/NetTest_Runner/test_tcp.c +++ b/Tools/NetTest_Runner/test_tcp.c @@ -19,9 +19,9 @@ static const int ERX_TIMEOUT = 1000; // Expect RX timeout (timeout=failure) static const int NRX_TIMEOUT = 250; // Not expect RX timeout (timeout=success) static const int RETX_TIMEOUT = 1000; // OS PARAM - Retransmit timeout -static const int LOST_TIMEOUT = 1000; // OS PARAM - Time before sending an ACK -static const int DACK_TIMEOUT = 500; // OS PARAM - Timeout for delayed ACKs -static const size_t DACK_BYTES = 4096; // OS PARAM - Threshold for delayed ACKs +//static const int LOST_TIMEOUT = 1000; // OS PARAM - Time before sending an ACK +//static const int DACK_TIMEOUT = 500; // OS PARAM - Timeout for delayed ACKs +//static const size_t DACK_BYTES = 4096; // OS PARAM - Threshold for delayed ACKs bool Test_TCP_Basic(void) { -- 2.20.1 From 230612b2efeeb769f1d96193ec01b10bd36d9873 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 18 Feb 2015 15:55:26 +0800 Subject: [PATCH 16/16] Usermode/libc - Fix strchr and strrchr behavior --- Usermode/Libraries/libc.so_src/string.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Usermode/Libraries/libc.so_src/string.c b/Usermode/Libraries/libc.so_src/string.c index d61d51dd..09481d86 100644 --- a/Usermode/Libraries/libc.so_src/string.c +++ b/Usermode/Libraries/libc.so_src/string.c @@ -184,15 +184,16 @@ EXPORT char *strndup(const char *str, size_t maxlen) /** * \fn EXPORT char *strchr(char *str, int character) * \brief Locate a character in a string + * \note The terminating NUL is part of the string */ EXPORT char *strchr(const char *_str, int character) { const unsigned char* str = (const unsigned char*)_str; - for(;*str;str++) + do { if( *str == character ) return (char*)str; - } + } while( *str++ ); return NULL; } @@ -203,11 +204,12 @@ EXPORT char *strchr(const char *_str, int character) EXPORT char *strrchr(const char *_str, int character) { const unsigned char* str = (const unsigned char*)_str; - for( size_t i = strlen(_str); i--; ) + size_t i = strlen(_str); + do { if(str[i] == character) return (void*)&str[i]; - } + } while( i -- ); return NULL; } -- 2.20.1