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