]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/ProxyResponder.c
mDNSResponder-58.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / ProxyResponder.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: ProxyResponder.c,v $
26 Revision 1.22 2003/08/14 02:19:55 cheshire
27 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
28
29 Revision 1.21 2003/08/12 19:56:26 cheshire
30 Update to APSL 2.0
31
32 Revision 1.20 2003/07/23 00:00:04 cheshire
33 Add comments
34
35 Revision 1.19 2003/07/15 01:55:16 cheshire
36 <rdar://problem/3315777> Need to implement service registration with subtypes
37
38 Revision 1.18 2003/07/02 21:19:58 cheshire
39 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
40
41 Revision 1.17 2003/05/26 03:21:29 cheshire
42 Tidy up address structure naming:
43 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
44 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
45 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
46
47 Revision 1.16 2003/05/26 03:01:28 cheshire
48 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
49
50 Revision 1.15 2003/05/06 00:00:50 cheshire
51 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
52
53 Revision 1.14 2003/04/25 01:45:57 cheshire
54 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
55
56 Revision 1.13 2003/04/18 22:46:12 cheshire
57 Fix mistake in 1.8 -- INADDR_NONE is 0xFFFFFFFF, not 0
58
59 Revision 1.12 2003/04/16 02:11:07 cheshire
60 Fixed mDNS_RegisterNoSuchService non-existance function so that it works again
61
62 Revision 1.11 2003/03/31 22:49:35 cheshire
63 Add "$Log" header
64
65 */
66
67 #include <stdio.h> // For printf()
68 #include <stdlib.h> // For exit() etc.
69 #include <string.h> // For strlen() etc.
70 #include <unistd.h> // For select()
71 #include <errno.h> // For errno, EINTR
72 #include <arpa/inet.h> // For inet_addr()
73 #include <netinet/in.h> // For INADDR_NONE
74 #include <netdb.h> // For gethostbyname()
75
76 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
77 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
78 #include "ExampleClientApp.h"
79
80 //*************************************************************************************************************
81 // Globals
82 static mDNS mDNSStorage; // mDNS core uses this to store its globals
83 static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
84
85 //*************************************************************************************************************
86 // Proxy Host Registration
87
88 typedef struct
89 {
90 mDNSv4Addr ip;
91 domainlabel hostlabel; // Conforms to standard DNS letter-digit-hyphen host name rules
92 AuthRecord RR_A; // 'A' (address) record for our ".local" name
93 AuthRecord RR_PTR; // PTR (reverse lookup) record
94 } ProxyHost;
95
96 mDNSlocal void HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
97 {
98 ProxyHost *f = (ProxyHost*)rr->RecordContext;
99 if (result == mStatus_NoError)
100 debugf("Host name successfully registered: %##s", &rr->resrec.name);
101 else
102 {
103 debugf("Host name conflict for %##s", &rr->resrec.name);
104 mDNS_Deregister(m, &f->RR_A);
105 mDNS_Deregister(m, &f->RR_PTR);
106 exit(-1);
107 }
108 }
109
110 mDNSlocal mStatus mDNS_RegisterProxyHost(mDNS *m, ProxyHost *p)
111 {
112 char buffer[32];
113
114 mDNS_SetupResourceRecord(&p->RR_A, mDNSNULL, mDNSInterface_Any, kDNSType_A, 60, kDNSRecordTypeUnique, HostNameCallback, p);
115 mDNS_SetupResourceRecord(&p->RR_PTR, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, HostNameCallback, p);
116
117 p->RR_A.resrec.name.c[0] = 0;
118 AppendDomainLabel(&p->RR_A.resrec.name, &p->hostlabel);
119 AppendLiteralLabelString(&p->RR_A.resrec.name, "local");
120
121 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p->ip.b[3], p->ip.b[2], p->ip.b[1], p->ip.b[0]);
122 MakeDomainNameFromDNSNameString(&p->RR_PTR.resrec.name, buffer);
123
124 p->RR_A. resrec.rdata->u.ip = p->ip;
125 p->RR_PTR.resrec.rdata->u.name = p->RR_A.resrec.name;
126
127 mDNS_Register(m, &p->RR_A);
128 mDNS_Register(m, &p->RR_PTR);
129
130 debugf("Made Proxy Host Records for %##s", &p->RR_A.resrec.name);
131
132 return(mStatus_NoError);
133 }
134
135 //*************************************************************************************************************
136 // Service Registration
137
138 // This sample ServiceCallback just calls mDNS_RenameAndReregisterService to automatically pick a new
139 // unique name for the service. For a device such as a printer, this may be appropriate.
140 // For a device with a user interface, and a screen, and a keyboard, the appropriate
141 // response may be to prompt the user and ask them to choose a new name for the service.
142 mDNSlocal void ServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
143 {
144 switch (result)
145 {
146 case mStatus_NoError: debugf("Callback: %##s Name Registered", &sr->RR_SRV.resrec.name); break;
147 case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", &sr->RR_SRV.resrec.name); break;
148 case mStatus_MemFree: debugf("Callback: %##s Memory Free", &sr->RR_SRV.resrec.name); break;
149 default: debugf("Callback: %##s Unknown Result %d", &sr->RR_SRV.resrec.name, result); break;
150 }
151
152 if (result == mStatus_NoError)
153 {
154 char buffer[256];
155 ConvertDomainNameToCString_unescaped(&sr->RR_SRV.resrec.name, buffer);
156 printf("Service %s now registered and active\n", buffer);
157 }
158
159 if (result == mStatus_NameConflict)
160 {
161 char buffer1[256], buffer2[256];
162 ConvertDomainNameToCString_unescaped(&sr->RR_SRV.resrec.name, buffer1);
163 mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
164 ConvertDomainNameToCString_unescaped(&sr->RR_SRV.resrec.name, buffer2);
165 printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2);
166 }
167 }
168
169 // RegisterService() is a simple wrapper function which takes C string
170 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
171 mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
172 const char name[], const char type[], const char domain[],
173 const domainname *host, mDNSu16 PortAsNumber, int argc, char **argv)
174 {
175 domainlabel n;
176 domainname t, d;
177 mDNSIPPort port;
178 unsigned char buffer[1024], *bptr = buffer;
179
180 MakeDomainLabelFromLiteralString(&n, name);
181 MakeDomainNameFromDNSNameString(&t, type);
182 MakeDomainNameFromDNSNameString(&d, domain);
183 port.b[0] = (mDNSu8)(PortAsNumber >> 8);
184 port.b[1] = (mDNSu8)(PortAsNumber );
185 while (argc)
186 {
187 int len = strlen(argv[0]);
188 printf("STR: %s\n", argv[0]);
189 bptr[0] = len;
190 strcpy(bptr+1, argv[0]);
191 bptr += 1 + len;
192 argc--;
193 argv++;
194 }
195
196 mDNS_RegisterService(m, recordset,
197 &n, &t, &d, // Name, type, domain
198 host, port, // Host and port
199 buffer, bptr-buffer, // TXT data, length
200 mDNSNULL, 0, // Subtypes
201 mDNSInterface_Any, // Interace ID
202 ServiceCallback, mDNSNULL); // Callback and context
203
204 ConvertDomainNameToCString_unescaped(&recordset->RR_SRV.resrec.name, buffer);
205 printf("Made Service Records for %s\n", buffer);
206 }
207
208 //*************************************************************************************************************
209 // Service non-existence assertion
210 // (claiming a service name without actually providing a service at that name, to prevent anyone else using that name)
211 // This is useful to avoid confusion between similar services
212 // e.g. A printer that implements IPP printing service using the name "My Printer", but doesn't implement LPR service,
213 // should also claim the LPR service name "My Printer" to stop a different printer offering LPR service under the same name,
214 // since it would be confusing to users to have two equivalent services with the same name.
215
216 mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
217 {
218 domainname *proxyhostname = (domainname *)rr->RecordContext;
219 switch (result)
220 {
221 case mStatus_NoError: debugf("Callback: %##s Name Registered", &rr->resrec.name); break;
222 case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", &rr->resrec.name); break;
223 case mStatus_MemFree: debugf("Callback: %##s Memory Free", &rr->resrec.name); break;
224 default: debugf("Callback: %##s Unknown Result %d", &rr->resrec.name, result); break;
225 }
226
227 if (result == mStatus_NoError)
228 {
229 char buffer[256];
230 ConvertDomainNameToCString_unescaped(&rr->resrec.name, buffer);
231 printf("Non-existence assertion %s now registered and active\n", buffer);
232 }
233
234 if (result == mStatus_NameConflict)
235 {
236 domainlabel n;
237 domainname t, d;
238 char buffer1[256], buffer2[256];
239 ConvertDomainNameToCString_unescaped(&rr->resrec.name, buffer1);
240 DeconstructServiceName(&rr->resrec.name, &n, &t, &d);
241 IncrementLabelSuffix(&n, mDNStrue);
242 mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, mDNSNULL);
243 ConvertDomainNameToCString_unescaped(&rr->resrec.name, buffer2);
244 printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2);
245 }
246 }
247
248 mDNSlocal void RegisterNoSuchService(mDNS *m, AuthRecord *const rr, domainname *proxyhostname,
249 const char name[], const char type[], const char domain[])
250 {
251 domainlabel n;
252 domainname t, d;
253 unsigned char buffer[256];
254 MakeDomainLabelFromLiteralString(&n, name);
255 MakeDomainNameFromDNSNameString(&t, type);
256 MakeDomainNameFromDNSNameString(&d, domain);
257 mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, proxyhostname);
258 ConvertDomainNameToCString_unescaped(&rr->resrec.name, buffer);
259 printf("Made Non-existence Record for %s\n", buffer);
260 }
261
262 //*************************************************************************************************************
263 // Main
264
265 mDNSexport int main(int argc, char **argv)
266 {
267 mStatus status;
268
269 if (argc < 3) goto usage;
270
271 status = mDNS_Init(&mDNSStorage, &PlatformStorage,
272 mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
273 mDNS_Init_DontAdvertiseLocalAddresses,
274 mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
275 if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); }
276
277 if (!strcmp(argv[1], "-"))
278 {
279 domainname proxyhostname;
280 AuthRecord proxyrecord;
281 if (argc < 5) goto usage;
282 proxyhostname.c[0] = 0;
283 AppendLiteralLabelString(&proxyhostname, argv[2]);
284 AppendLiteralLabelString(&proxyhostname, "local");
285 RegisterNoSuchService(&mDNSStorage, &proxyrecord, &proxyhostname, argv[3], argv[4], "local.");
286 ExampleClientEventLoop(&mDNSStorage);
287 mDNS_Close(&mDNSStorage);
288 }
289 else
290 {
291 ProxyHost proxyhost;
292 ServiceRecordSet proxyservice;
293
294 proxyhost.ip.NotAnInteger = inet_addr(argv[1]);
295 if (proxyhost.ip.NotAnInteger == INADDR_NONE) // INADDR_NONE is 0xFFFFFFFF
296 {
297 struct hostent *h = gethostbyname(argv[1]);
298 if (h) proxyhost.ip.NotAnInteger = *(long*)h->h_addr;
299 }
300 if (proxyhost.ip.NotAnInteger == INADDR_NONE) // INADDR_NONE is 0xFFFFFFFF
301 {
302 fprintf(stderr, "%s is not valid host address\n", argv[1]);
303 return(-1);
304 }
305
306 MakeDomainLabelFromLiteralString(&proxyhost.hostlabel, argv[2]);
307
308 mDNS_RegisterProxyHost(&mDNSStorage, &proxyhost);
309
310 if (argc >=6)
311 RegisterService(&mDNSStorage, &proxyservice, argv[3], argv[4], "local.",
312 &proxyhost.RR_A.resrec.name, atoi(argv[5]), argc-6, &argv[6]);
313
314 ExampleClientEventLoop(&mDNSStorage);
315 mDNS_Close(&mDNSStorage);
316 }
317
318 return(0);
319
320 usage:
321 fprintf(stderr, "%s ip hostlabel [srvname srvtype port txt [txt ...]]\n", argv[0]);
322 fprintf(stderr, "ip Real IP address (or valid host name) of the host where the service actually resides\n");
323 fprintf(stderr, "hostlabel First label of the dot-local host name to create for this host, e.g. \"foo\" for \"foo.local.\"\n");
324 fprintf(stderr, "srvname Descriptive name of service, e.g. \"Stuart's Ink Jet Printer\"\n");
325 fprintf(stderr, "srvtype IANA service type, e.g. \"_ipp._tcp\" or \"_ssh._tcp\", etc.\n");
326 fprintf(stderr, "port Port number where the service resides (1-65535)\n");
327 fprintf(stderr, "txt Additional name/value pairs specified in service definition, e.g. \"pdl=application/postscript\"\n");
328 fprintf(stderr, "e.g. %s 169.254.12.34 thehost (just create a dot-local host name)\n", argv[0]);
329 fprintf(stderr, "or %s 169.254.12.34 thehost \"My Printer\" _printer._tcp. 515 rp=lpt1 pdl=application/postscript\n", argv[0]);
330 fprintf(stderr, "or %s - thehost \"My Printer\" _printer._tcp. (assertion of non-existence)\n", argv[0]);
331 return(-1);
332 }