#include "unittest_common.h" #include "dns_sd.h" #include "mDNSEmbeddedAPI.h" #include "mDNSMacOSX.h" static mDNS_PlatformSupport PlatformStorage; #define RR_CACHE_SIZE ((32*1024) / sizeof(CacheRecord)) static CacheEntity gRrcachestorage[RR_CACHE_SIZE]; // Primary interface info that is used when simulating the receive of the response packet mDNSInterfaceID primary_interfaceID; mDNSAddr primary_v4; mDNSAddr primary_v6; mDNSAddr primary_router; // This function sets up the minimum environement to run a unit test. It // initializes logging, interfaces, and timenow. mDNSexport mStatus init_mdns_environment(mDNSBool enableLogging) { mDNS *m = &mDNSStorage; init_logging_ut(); mDNS_LoggingEnabled = enableLogging; mDNS_PacketLoggingEnabled = enableLogging; mStatus result = mDNS_InitStorage_ut(m, &PlatformStorage, gRrcachestorage, RR_CACHE_SIZE, mDNSfalse, mDNSNULL, mDNSNULL); if (result != mStatus_NoError) return result; primary_v4 = primary_v6 = primary_router = zeroAddr; SetInterfaces_ut(&primary_interfaceID, &primary_v4, &primary_v6, &primary_router); m->timenow = mDNS_TimeNow_NoLock(m); return mStatus_NoError; } // This function sets up the minimum environement to run a unit test. It // initializes logging and timenow. This is the call to use if your // unit test does not use interfaces. mDNSexport mStatus init_mdns_storage(void) { mDNS *m = &mDNSStorage; init_logging_ut(); mDNS_LoggingEnabled = 1; mDNS_PacketLoggingEnabled = 1; mStatus result = mDNS_InitStorage_ut(m, &PlatformStorage, gRrcachestorage, RR_CACHE_SIZE, mDNSfalse, mDNSNULL, mDNSNULL); if (result != mStatus_NoError) return result; return mStatus_NoError; } mDNSlocal void init_client_request(request_state* req, const uint8_t *msgbuf, uint32_t msgSize, uint32_t op) { // Simulate read_msg behavior since unit test does not open a socket memset(req, 0, sizeof(request_state)); req->ts = t_complete; req->msgbuf = mDNSNULL; req->msgptr = msgbuf; req->msgend = msgbuf + msgSize; // The rest of the request values are set in order to simulate a request req->sd = client_req_sd; req->uid = client_req_uid; req->hdr_bytes = client_req_hdr_bytes; req->hdr.version = client_req_hdr_version; req->hdr.op = op; // query_request req->hdr.datalen = msgSize; req->data_bytes = msgSize; req->process_id = client_req_process_id; memcpy(req->pid_name, client_req_pid_name, strlen(client_req_pid_name)); } // This function calls the mDNSResponder handle_client_request() API. It initializes // the request and query data structures. mDNSexport mStatus start_client_request(request_state* req, const uint8_t *msgbuf, uint32_t msgsz, uint32_t op, UDPSocket* socket) { // Process the unit test's client request init_client_request(req, msgbuf, msgsz, op); mStatus result = handle_client_request_ut((void*)req); DNSQuestion* q = &req->queryrecord->op.q; q->LocalSocket = socket; return result; } // This function calls the mDNSResponder mDNSCoreReceive() API. mDNSexport void receive_response(const request_state* req, DNSMessage *msg, size_t msgSize) { mDNS *m = &mDNSStorage; mDNSAddr srcaddr; mDNSIPPort srcport, dstport; const mDNSu8 * end; DNSQuestion *q = (DNSQuestion *)&req->queryrecord->op.q; UInt8* data = (UInt8*)msg; // Used same values for DNS server as specified during init of unit test srcaddr.type = mDNSAddrType_IPv4; srcaddr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger; srcport.NotAnInteger = client_resp_src_port; // Used random value for dstport dstport.NotAnInteger = swap16((mDNSu16)client_resp_dst_port); // Set DNS message (that was copied from a WireShark packet) end = (const mDNSu8 *)msg + msgSize; // Set socket info that mDNSCoreReceive uses to verify socket context q->LocalSocket->ss.port.NotAnInteger = swap16((mDNSu16)client_resp_dst_port); q->TargetQID.b[0] = data[0]; q->TargetQID.b[1] = data[1]; // Execute mDNSCoreReceive which copies two DNS records into the cache mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &primary_v4, dstport, primary_interfaceID); } mDNSexport size_t get_reply_len(char* name, uint16_t rdlen) { size_t len = sizeof(DNSServiceFlags); len += sizeof(mDNSu32); // interface index len += sizeof(DNSServiceErrorType); len += strlen(name) + 1; len += 3 * sizeof(mDNSu16); // type, class, rdlen len += rdlen; len += sizeof(mDNSu32); // TTL return len; } void free_req(request_state* req) { // Cleanup request's memory usage while (req->replies) { reply_state *reply = req->replies; req->replies = req->replies->next; mDNSPlatformMemFree(reply); } req->replies = NULL; mDNSPlatformMemFree(req); } // Unit test support functions follow #define SA_LEN(addr) (((addr)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) mDNSexport void get_ip(const char *const name, struct sockaddr_storage *result) { struct addrinfo* aiList; int err = getaddrinfo(name, NULL, NULL, &aiList); if (err) fprintf(stderr, "getaddrinfo error %d for %s", err, name); else memcpy(result, aiList->ai_addr, SA_LEN(aiList->ai_addr)); if (aiList) freeaddrinfo(aiList); } // The AddDNSServer_ut function adds a dns server to mDNSResponder's list. mDNSexport mStatus AddDNSServerScoped_ut(mDNSInterfaceID interfaceID, ScopeType scoped) { mDNS *m = &mDNSStorage; m->timenow = 0; mDNS_Lock(m); domainname d; mDNSAddr addr; mDNSIPPort port; mDNSs32 serviceID = 0; mDNSu32 timeout = dns_server_timeout; mDNSBool cellIntf = 0; mDNSBool isExpensive = 0; mDNSBool isConstrained = 0; mDNSBool isCLAT46 = mDNSfalse; mDNSu32 resGroupID = dns_server_resGroupID; mDNSBool reqA = mDNStrue; mDNSBool reqAAAA = mDNStrue; mDNSBool reqDO = mDNSfalse; d.c[0] = 0; addr.type = mDNSAddrType_IPv4; addr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger; port.NotAnInteger = client_resp_src_port; mDNS_AddDNSServer(m, &d, interfaceID, serviceID, &addr, port, scoped, timeout, cellIntf, isExpensive, isConstrained, isCLAT46, resGroupID, reqA, reqAAAA, reqDO); mDNS_Unlock(m); return mStatus_NoError; } mDNSexport mStatus AddDNSServer_ut(void) { return AddDNSServerScoped_ut(primary_interfaceID, kScopeNone); } mDNSexport mStatus force_uDNS_SetupDNSConfig_ut(mDNS *const m) { m->p->LastConfigGeneration = 0; return uDNS_SetupDNSConfig(m); } mDNSexport mStatus verify_cache_addr_order_for_domain_ut(mDNS *const m, mDNSu8* octet, mDNSu32 count, const domainname *const name) { mStatus result = mStatus_NoError; const CacheGroup *cg = CacheGroupForName(m, DomainNameHashValue(name), name); if (cg) { mDNSu32 i; CacheRecord **rp = (CacheRecord **)&cg->members; for (i = 0 ; *rp && i < count ; i++ ) { if ((*rp)->resrec.rdata->u.ipv4.b[3] != octet[i]) { LogInfo ("Octet %d compare failed %d != %d", i, (*rp)->resrec.rdata->u.ipv4.b[3], octet[i]); break; } rp = &(*rp)->next; } if (i != count) result = mStatus_Invalid; } else { LogInfo ("Cache group not found"); result = mStatus_Invalid; } return result; }