1 #include "unittest_common.h"
3 #include "mDNSEmbeddedAPI.h"
4 #include "mDNSMacOSX.h"
6 static mDNS_PlatformSupport PlatformStorage
;
7 #define RR_CACHE_SIZE ((32*1024) / sizeof(CacheRecord))
8 static CacheEntity gRrcachestorage
[RR_CACHE_SIZE
];
10 // Primary interface info that is used when simulating the receive of the response packet
11 mDNSInterfaceID primary_interfaceID
;
14 mDNSAddr primary_router
;
16 // This function sets up the minimum environement to run a unit test. It
17 // initializes logging, interfaces, and timenow.
18 mDNSexport mStatus
init_mdns_environment(mDNSBool enableLogging
)
20 mDNS
*m
= &mDNSStorage
;
23 mDNS_LoggingEnabled
= enableLogging
;
24 mDNS_PacketLoggingEnabled
= enableLogging
;
26 mStatus result
= mDNS_InitStorage_ut(m
, &PlatformStorage
, gRrcachestorage
, RR_CACHE_SIZE
, mDNSfalse
, mDNSNULL
, mDNSNULL
);
27 if (result
!= mStatus_NoError
)
30 primary_v4
= primary_v6
= primary_router
= zeroAddr
;
31 SetInterfaces_ut(&primary_interfaceID
, &primary_v4
, &primary_v6
, &primary_router
);
33 m
->timenow
= mDNS_TimeNow_NoLock(m
);
34 return mStatus_NoError
;
37 // This function sets up the minimum environement to run a unit test. It
38 // initializes logging and timenow. This is the call to use if your
39 // unit test does not use interfaces.
40 mDNSexport mStatus
init_mdns_storage()
42 mDNS
*m
= &mDNSStorage
;
45 mDNS_LoggingEnabled
= 1;
46 mDNS_PacketLoggingEnabled
= 1;
48 mStatus result
= mDNS_InitStorage_ut(m
, &PlatformStorage
, gRrcachestorage
, RR_CACHE_SIZE
, mDNSfalse
, mDNSNULL
, mDNSNULL
);
49 if (result
!= mStatus_NoError
)
52 return mStatus_NoError
;
55 mDNSlocal
void init_client_request(request_state
* req
, char *msgbuf
, size_t msgSize
, uint32_t op
)
57 // Simulate read_msg behavior since unit test does not open a socket
58 memset(req
, 0, sizeof(request_state
));
61 req
->msgbuf
= mDNSNULL
;
63 req
->msgend
= msgbuf
+ msgSize
;
65 // The rest of the request values are set in order to simulate a request
66 req
->sd
= client_req_sd
;
67 req
->uid
= client_req_uid
;
68 req
->hdr_bytes
= client_req_hdr_bytes
;
69 req
->hdr
.version
= client_req_hdr_version
;
70 req
->hdr
.op
= op
; // query_request
71 req
->hdr
.datalen
= msgSize
;
72 req
->data_bytes
= msgSize
;
73 req
->process_id
= client_req_process_id
;
74 memcpy(req
->pid_name
, client_req_pid_name
, strlen(client_req_pid_name
));
77 // This function calls the mDNSResponder handle_client_request() API. It initializes
78 // the request and query data structures.
79 mDNSexport mStatus
start_client_request(request_state
* req
, char *msgbuf
, size_t msgsz
, uint32_t op
, UDPSocket
* socket
)
81 // Process the unit test's client request
82 init_client_request(req
, msgbuf
, msgsz
, op
);
84 mStatus result
= handle_client_request_ut((void*)req
);
85 DNSQuestion
* q
= &req
->u
.queryrecord
.op
.q
;
86 q
->LocalSocket
= socket
;
90 // This function calls the mDNSResponder mDNSCoreReceive() API.
91 mDNSexport
void receive_response(const request_state
* req
, DNSMessage
*msg
, size_t msgSize
)
93 mDNS
*m
= &mDNSStorage
;
95 mDNSIPPort srcport
, dstport
;
97 DNSQuestion
*q
= (DNSQuestion
*)&req
->u
.queryrecord
.op
.q
;
98 UInt8
* data
= (UInt8
*)msg
;
100 // Used same values for DNS server as specified during init of unit test
101 srcaddr
.type
= mDNSAddrType_IPv4
;
102 srcaddr
.ip
.v4
.NotAnInteger
= dns_server_ipv4
.NotAnInteger
;
103 srcport
.NotAnInteger
= client_resp_src_port
;
105 // Used random value for dstport
106 dstport
.NotAnInteger
= swap16((mDNSu16
)client_resp_dst_port
);
108 // Set DNS message (that was copied from a WireShark packet)
109 end
= (const mDNSu8
*)msg
+ msgSize
;
111 // Set socket info that mDNSCoreReceive uses to verify socket context
112 q
->LocalSocket
->ss
.port
.NotAnInteger
= swap16((mDNSu16
)client_resp_dst_port
);
113 q
->TargetQID
.b
[0] = data
[0];
114 q
->TargetQID
.b
[1] = data
[1];
116 // Execute mDNSCoreReceive which copies two DNS records into the cache
117 mDNSCoreReceive(m
, msg
, end
, &srcaddr
, srcport
, &primary_v4
, dstport
, primary_interfaceID
);
120 mDNSexport
void receive_suspicious_response_ut(const request_state
* req
, DNSMessage
*msg
, size_t msgSize
, mDNSOpaque16 suspiciousqid
, mDNSBool goodLastQID
)
122 mDNS
*m
= &mDNSStorage
;
124 mDNSIPPort srcport
, dstport
;
126 DNSQuestion
*q
= (DNSQuestion
*)&req
->u
.queryrecord
.op
.q
;
127 UInt8
* data
= (UInt8
*)msg
;
129 // Used same values for DNS server as specified during init of unit test
130 srcaddr
.type
= mDNSAddrType_IPv4
;
131 srcaddr
.ip
.v4
.NotAnInteger
= dns_server_ipv4
.NotAnInteger
;
132 srcport
.NotAnInteger
= client_resp_src_port
;
134 // Used random value for dstport
135 dstport
.NotAnInteger
= swap16((mDNSu16
)client_resp_dst_port
);
137 // Set DNS message (that was copied from a WireShark packet)
138 end
= (const mDNSu8
*)msg
+ msgSize
;
140 // Set socket info that mDNSCoreReceive uses to verify socket context
141 q
->LocalSocket
->ss
.port
.NotAnInteger
= swap16((mDNSu16
)client_resp_dst_port
);
142 if (suspiciousqid
.NotAnInteger
)
144 q
->TargetQID
.NotAnInteger
= swap16(suspiciousqid
.NotAnInteger
);
147 q
->LastTargetQID
.b
[0] = data
[0];
148 q
->LastTargetQID
.b
[1] = data
[1];
150 else q
->LastTargetQID
.NotAnInteger
= 0;
154 q
->TargetQID
.b
[0] = data
[0];
155 q
->TargetQID
.b
[1] = data
[1];
158 // Execute mDNSCoreReceive which copies two DNS records into the cache
159 mDNSCoreReceive(m
, msg
, end
, &srcaddr
, srcport
, &primary_v4
, dstport
, primary_interfaceID
);
162 mDNSexport
size_t get_reply_len(char* name
, uint16_t rdlen
)
164 size_t len
= sizeof(DNSServiceFlags
);
165 len
+= sizeof(mDNSu32
); // interface index
166 len
+= sizeof(DNSServiceErrorType
);
167 len
+= strlen(name
) + 1;
168 len
+= 3 * sizeof(mDNSu16
); // type, class, rdlen
170 len
+= sizeof(mDNSu32
); // TTL
175 void free_req(request_state
* req
)
177 // Cleanup request's memory usage
180 reply_state
*reply
= req
->replies
;
181 req
->replies
= req
->replies
->next
;
182 mDNSPlatformMemFree(reply
);
185 mDNSPlatformMemFree(req
);
188 // Unit test support functions follow
189 #define SA_LEN(addr) (((addr)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
191 mDNSexport
void get_ip(const char *const name
, struct sockaddr_storage
*result
)
193 struct addrinfo
* aiList
;
194 int err
= getaddrinfo(name
, NULL
, NULL
, &aiList
);
195 if (err
) fprintf(stderr
, "getaddrinfo error %d for %s", err
, name
);
196 else memcpy(result
, aiList
->ai_addr
, SA_LEN(aiList
->ai_addr
));
197 if (aiList
) freeaddrinfo(aiList
);
200 // The AddDNSServer_ut function adds a dns server to mDNSResponder's list.
201 mDNSexport mStatus
AddDNSServerScoped_ut(mDNSInterfaceID interfaceID
, ScopeType scoped
)
203 mDNS
*m
= &mDNSStorage
;
209 mDNSs32 serviceID
= 0;
210 mDNSu32 timeout
= dns_server_timeout
;
211 mDNSBool cellIntf
= 0;
212 mDNSBool isExpensive
= 0;
213 mDNSBool isConstrained
= 0;
214 mDNSBool isCLAT46
= mDNSfalse
;
215 mDNSu32 resGroupID
= dns_server_resGroupID
;
216 mDNSBool reqA
= mDNStrue
;
217 mDNSBool reqAAAA
= mDNStrue
;
218 mDNSBool reqDO
= mDNSfalse
;
220 addr
.type
= mDNSAddrType_IPv4
;
221 addr
.ip
.v4
.NotAnInteger
= dns_server_ipv4
.NotAnInteger
;
222 port
.NotAnInteger
= client_resp_src_port
;
223 mDNS_AddDNSServer(m
, &d
, interfaceID
, serviceID
, &addr
, port
, scoped
, timeout
,
224 cellIntf
, isExpensive
, isConstrained
, isCLAT46
, resGroupID
,
225 reqA
, reqAAAA
, reqDO
);
227 return mStatus_NoError
;
230 mDNSexport mStatus
AddDNSServer_ut(void)
232 return AddDNSServerScoped_ut(primary_interfaceID
, kScopeNone
);
235 mDNSexport mStatus
force_uDNS_SetupDNSConfig_ut(mDNS
*const m
)
237 m
->p
->LastConfigGeneration
= 0;
238 return uDNS_SetupDNSConfig(m
);
241 mDNSexport mStatus
verify_cache_addr_order_for_domain_ut(mDNS
*const m
, mDNSu8
* octet
, mDNSu32 count
, const domainname
*const name
)
243 mStatus result
= mStatus_NoError
;
244 const CacheGroup
*cg
= CacheGroupForName(m
, DomainNameHashValue(name
), name
);
248 CacheRecord
**rp
= (CacheRecord
**)&cg
->members
;
249 for (i
= 0 ; *rp
&& i
< count
; i
++ )
251 if ((*rp
)->resrec
.rdata
->u
.ipv4
.b
[3] != octet
[i
])
253 LogInfo ("Octet %d compare failed %d != %d", i
, (*rp
)->resrec
.rdata
->u
.ipv4
.b
[3], octet
[i
]);
258 if (i
!= count
) result
= mStatus_Invalid
;
262 LogInfo ("Cache group not found");
263 result
= mStatus_Invalid
;