summaryrefslogtreecommitdiffstats
path: root/mDNSResponder/unittests/unittest_common.c
blob: 397180598c2ac7f042fc30e2d6f0c15061ffde6d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#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()
{
	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, char *msgbuf, size_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, char *msgbuf, size_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->u.queryrecord.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->u.queryrecord.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);
}