2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: ProxyResponder.c,v $
26 Revision 1.24 2003/11/14 21:27:09 cheshire
27 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
28 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
30 Revision 1.23 2003/10/30 19:39:28 cheshire
31 Fix warnings on certain compilers
33 Revision 1.22 2003/08/14 02:19:55 cheshire
34 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
36 Revision 1.21 2003/08/12 19:56:26 cheshire
39 Revision 1.20 2003/07/23 00:00:04 cheshire
42 Revision 1.19 2003/07/15 01:55:16 cheshire
43 <rdar://problem/3315777> Need to implement service registration with subtypes
45 Revision 1.18 2003/07/02 21:19:58 cheshire
46 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
48 Revision 1.17 2003/05/26 03:21:29 cheshire
49 Tidy up address structure naming:
50 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
51 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
52 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
54 Revision 1.16 2003/05/26 03:01:28 cheshire
55 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
57 Revision 1.15 2003/05/06 00:00:50 cheshire
58 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
60 Revision 1.14 2003/04/25 01:45:57 cheshire
61 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
63 Revision 1.13 2003/04/18 22:46:12 cheshire
64 Fix mistake in 1.8 -- INADDR_NONE is 0xFFFFFFFF, not 0
66 Revision 1.12 2003/04/16 02:11:07 cheshire
67 Fixed mDNS_RegisterNoSuchService non-existence function so that it works again
69 Revision 1.11 2003/03/31 22:49:35 cheshire
74 #include <stdio.h> // For printf()
75 #include <stdlib.h> // For exit() etc.
76 #include <string.h> // For strlen() etc.
77 #include <unistd.h> // For select()
78 #include <errno.h> // For errno, EINTR
79 #include <arpa/inet.h> // For inet_addr()
80 #include <netinet/in.h> // For INADDR_NONE
81 #include <netdb.h> // For gethostbyname()
83 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
84 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
85 #include "ExampleClientApp.h"
87 //*************************************************************************************************************
89 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
90 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
92 //*************************************************************************************************************
93 // Proxy Host Registration
98 domainlabel hostlabel
; // Conforms to standard DNS letter-digit-hyphen host name rules
99 AuthRecord RR_A
; // 'A' (address) record for our ".local" name
100 AuthRecord RR_PTR
; // PTR (reverse lookup) record
103 mDNSlocal
void HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
105 ProxyHost
*f
= (ProxyHost
*)rr
->RecordContext
;
106 if (result
== mStatus_NoError
)
107 debugf("Host name successfully registered: %##s", &rr
->resrec
.name
);
110 debugf("Host name conflict for %##s", &rr
->resrec
.name
);
111 mDNS_Deregister(m
, &f
->RR_A
);
112 mDNS_Deregister(m
, &f
->RR_PTR
);
117 mDNSlocal mStatus
mDNS_RegisterProxyHost(mDNS
*m
, ProxyHost
*p
)
121 mDNS_SetupResourceRecord(&p
->RR_A
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, 60, kDNSRecordTypeUnique
, HostNameCallback
, p
);
122 mDNS_SetupResourceRecord(&p
->RR_PTR
, mDNSNULL
, mDNSInterface_Any
, kDNSType_PTR
, 60, kDNSRecordTypeKnownUnique
, HostNameCallback
, p
);
124 p
->RR_A
.resrec
.name
.c
[0] = 0;
125 AppendDomainLabel(&p
->RR_A
.resrec
.name
, &p
->hostlabel
);
126 AppendLiteralLabelString(&p
->RR_A
.resrec
.name
, "local");
128 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]);
129 MakeDomainNameFromDNSNameString(&p
->RR_PTR
.resrec
.name
, buffer
);
131 p
->RR_A
. resrec
.rdata
->u
.ip
= p
->ip
;
132 p
->RR_PTR
.resrec
.rdata
->u
.name
= p
->RR_A
.resrec
.name
;
134 mDNS_Register(m
, &p
->RR_A
);
135 mDNS_Register(m
, &p
->RR_PTR
);
137 debugf("Made Proxy Host Records for %##s", &p
->RR_A
.resrec
.name
);
139 return(mStatus_NoError
);
142 //*************************************************************************************************************
143 // Service Registration
145 // This sample ServiceCallback just calls mDNS_RenameAndReregisterService to automatically pick a new
146 // unique name for the service. For a device such as a printer, this may be appropriate.
147 // For a device with a user interface, and a screen, and a keyboard, the appropriate
148 // response may be to prompt the user and ask them to choose a new name for the service.
149 mDNSlocal
void ServiceCallback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
153 case mStatus_NoError
: debugf("Callback: %##s Name Registered", &sr
->RR_SRV
.resrec
.name
); break;
154 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", &sr
->RR_SRV
.resrec
.name
); break;
155 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", &sr
->RR_SRV
.resrec
.name
); break;
156 default: debugf("Callback: %##s Unknown Result %d", &sr
->RR_SRV
.resrec
.name
, result
); break;
159 if (result
== mStatus_NoError
)
161 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
162 ConvertDomainNameToCString(&sr
->RR_SRV
.resrec
.name
, buffer
);
163 printf("Service %s now registered and active\n", buffer
);
166 if (result
== mStatus_NameConflict
)
168 char buffer1
[MAX_ESCAPED_DOMAIN_NAME
], buffer2
[MAX_ESCAPED_DOMAIN_NAME
];
169 ConvertDomainNameToCString(&sr
->RR_SRV
.resrec
.name
, buffer1
);
170 mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
171 ConvertDomainNameToCString(&sr
->RR_SRV
.resrec
.name
, buffer2
);
172 printf("Name Conflict! %s renamed as %s\n", buffer1
, buffer2
);
176 // RegisterService() is a simple wrapper function which takes C string
177 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
178 mDNSlocal
void RegisterService(mDNS
*m
, ServiceRecordSet
*recordset
,
179 const char name
[], const char type
[], const char domain
[],
180 const domainname
*host
, mDNSu16 PortAsNumber
, int argc
, char **argv
)
185 unsigned char txtbuffer
[1024], *bptr
= txtbuffer
;
186 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
188 MakeDomainLabelFromLiteralString(&n
, name
);
189 MakeDomainNameFromDNSNameString(&t
, type
);
190 MakeDomainNameFromDNSNameString(&d
, domain
);
191 port
.b
[0] = (mDNSu8
)(PortAsNumber
>> 8);
192 port
.b
[1] = (mDNSu8
)(PortAsNumber
);
195 int len
= strlen(argv
[0]);
196 printf("STR: %s\n", argv
[0]);
198 strcpy((char*)(bptr
+1), argv
[0]);
204 mDNS_RegisterService(m
, recordset
,
205 &n
, &t
, &d
, // Name, type, domain
206 host
, port
, // Host and port
207 txtbuffer
, bptr
-txtbuffer
, // TXT data, length
208 mDNSNULL
, 0, // Subtypes
209 mDNSInterface_Any
, // Interace ID
210 ServiceCallback
, mDNSNULL
); // Callback and context
212 ConvertDomainNameToCString(&recordset
->RR_SRV
.resrec
.name
, buffer
);
213 printf("Made Service Records for %s\n", buffer
);
216 //*************************************************************************************************************
217 // Service non-existence assertion
218 // (claiming a service name without actually providing a service at that name, to prevent anyone else using that name)
219 // This is useful to avoid confusion between similar services
220 // e.g. A printer that implements IPP printing service using the name "My Printer", but doesn't implement LPR service,
221 // should also claim the LPR service name "My Printer" to stop a different printer offering LPR service under the same name,
222 // since it would be confusing to users to have two equivalent services with the same name.
224 mDNSlocal
void NoSuchServiceCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
226 domainname
*proxyhostname
= (domainname
*)rr
->RecordContext
;
229 case mStatus_NoError
: debugf("Callback: %##s Name Registered", &rr
->resrec
.name
); break;
230 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", &rr
->resrec
.name
); break;
231 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", &rr
->resrec
.name
); break;
232 default: debugf("Callback: %##s Unknown Result %d", &rr
->resrec
.name
, result
); break;
235 if (result
== mStatus_NoError
)
237 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
238 ConvertDomainNameToCString(&rr
->resrec
.name
, buffer
);
239 printf("Non-existence assertion %s now registered and active\n", buffer
);
242 if (result
== mStatus_NameConflict
)
246 char buffer1
[MAX_ESCAPED_DOMAIN_NAME
], buffer2
[MAX_ESCAPED_DOMAIN_NAME
];
247 ConvertDomainNameToCString(&rr
->resrec
.name
, buffer1
);
248 DeconstructServiceName(&rr
->resrec
.name
, &n
, &t
, &d
);
249 IncrementLabelSuffix(&n
, mDNStrue
);
250 mDNS_RegisterNoSuchService(m
, rr
, &n
, &t
, &d
, proxyhostname
, mDNSInterface_Any
, NoSuchServiceCallback
, mDNSNULL
);
251 ConvertDomainNameToCString(&rr
->resrec
.name
, buffer2
);
252 printf("Name Conflict! %s renamed as %s\n", buffer1
, buffer2
);
256 mDNSlocal
void RegisterNoSuchService(mDNS
*m
, AuthRecord
*const rr
, domainname
*proxyhostname
,
257 const char name
[], const char type
[], const char domain
[])
261 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
262 MakeDomainLabelFromLiteralString(&n
, name
);
263 MakeDomainNameFromDNSNameString(&t
, type
);
264 MakeDomainNameFromDNSNameString(&d
, domain
);
265 mDNS_RegisterNoSuchService(m
, rr
, &n
, &t
, &d
, proxyhostname
, mDNSInterface_Any
, NoSuchServiceCallback
, proxyhostname
);
266 ConvertDomainNameToCString(&rr
->resrec
.name
, buffer
);
267 printf("Made Non-existence Record for %s\n", buffer
);
270 //*************************************************************************************************************
273 mDNSexport
int main(int argc
, char **argv
)
277 if (argc
< 3) goto usage
;
279 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
280 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
281 mDNS_Init_DontAdvertiseLocalAddresses
,
282 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
283 if (status
) { fprintf(stderr
, "Daemon start: mDNS_Init failed %ld\n", status
); return(status
); }
285 if (!strcmp(argv
[1], "-"))
287 domainname proxyhostname
;
288 AuthRecord proxyrecord
;
289 if (argc
< 5) goto usage
;
290 proxyhostname
.c
[0] = 0;
291 AppendLiteralLabelString(&proxyhostname
, argv
[2]);
292 AppendLiteralLabelString(&proxyhostname
, "local");
293 RegisterNoSuchService(&mDNSStorage
, &proxyrecord
, &proxyhostname
, argv
[3], argv
[4], "local.");
294 ExampleClientEventLoop(&mDNSStorage
);
295 mDNS_Close(&mDNSStorage
);
300 ServiceRecordSet proxyservice
;
302 proxyhost
.ip
.NotAnInteger
= inet_addr(argv
[1]);
303 if (proxyhost
.ip
.NotAnInteger
== INADDR_NONE
) // INADDR_NONE is 0xFFFFFFFF
305 struct hostent
*h
= gethostbyname(argv
[1]);
306 if (h
) proxyhost
.ip
.NotAnInteger
= *(long*)h
->h_addr
;
308 if (proxyhost
.ip
.NotAnInteger
== INADDR_NONE
) // INADDR_NONE is 0xFFFFFFFF
310 fprintf(stderr
, "%s is not valid host address\n", argv
[1]);
314 MakeDomainLabelFromLiteralString(&proxyhost
.hostlabel
, argv
[2]);
316 mDNS_RegisterProxyHost(&mDNSStorage
, &proxyhost
);
319 RegisterService(&mDNSStorage
, &proxyservice
, argv
[3], argv
[4], "local.",
320 &proxyhost
.RR_A
.resrec
.name
, atoi(argv
[5]), argc
-6, &argv
[6]);
322 ExampleClientEventLoop(&mDNSStorage
);
323 mDNS_Close(&mDNSStorage
);
329 fprintf(stderr
, "%s ip hostlabel [srvname srvtype port txt [txt ...]]\n", argv
[0]);
330 fprintf(stderr
, "ip Real IP address (or valid host name) of the host where the service actually resides\n");
331 fprintf(stderr
, "hostlabel First label of the dot-local host name to create for this host, e.g. \"foo\" for \"foo.local.\"\n");
332 fprintf(stderr
, "srvname Descriptive name of service, e.g. \"Stuart's Ink Jet Printer\"\n");
333 fprintf(stderr
, "srvtype IANA service type, e.g. \"_ipp._tcp\" or \"_ssh._tcp\", etc.\n");
334 fprintf(stderr
, "port Port number where the service resides (1-65535)\n");
335 fprintf(stderr
, "txt Additional name/value pairs specified in service definition, e.g. \"pdl=application/postscript\"\n");
336 fprintf(stderr
, "e.g. %s 169.254.12.34 thehost (just create a dot-local host name)\n", argv
[0]);
337 fprintf(stderr
, "or %s 169.254.12.34 thehost \"My Printer\" _printer._tcp. 515 rp=lpt1 pdl=application/postscript\n", argv
[0]);
338 fprintf(stderr
, "or %s - thehost \"My Printer\" _printer._tcp. (assertion of non-existence)\n", argv
[0]);