import latest mDNSResponder

This commit is contained in:
christos 2018-01-14 18:43:01 +00:00
parent ee071a7a97
commit d3be8271c6
44 changed files with 47593 additions and 29345 deletions

View File

@ -39,37 +39,37 @@
*/
#include <ctype.h>
#include <stdio.h> // For stdout, stderr
#include <stdio.h> // For stdout, stderr
#include "ClientCommon.h"
const char *GetNextLabel(const char *cstr, char label[64])
{
char *ptr = label;
while (*cstr && *cstr != '.') // While we have characters in the label...
{
char c = *cstr++;
if (c == '\\' && *cstr) // If we have a backslash, and it's not the last character of the string
{
c = *cstr++;
if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1]))
{
int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal
int v1 = cstr[ 0] - '0';
int v2 = cstr[ 1] - '0';
int val = v0 * 100 + v1 * 10 + v2;
// If valid three-digit decimal value, use it
// Note that although ascii nuls are possible in DNS labels
// we're building a C string here so we have no way to represent that
if (val == 0) val = '-';
if (val <= 255) { c = (char)val; cstr += 2; }
}
}
*ptr++ = c;
if (ptr >= label+64) { label[63] = 0; return(NULL); } // Illegal label more than 63 bytes
}
*ptr = 0; // Null-terminate label text
if (ptr == label) return(NULL); // Illegal empty label
if (*cstr) cstr++; // Skip over the trailing dot (if present)
return(cstr);
}
{
char *ptr = label;
while (*cstr && *cstr != '.') // While we have characters in the label...
{
char c = *cstr++;
if (c == '\\' && *cstr) // If we have a backslash, and it's not the last character of the string
{
c = *cstr++;
if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1]))
{
int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal
int v1 = cstr[ 0] - '0';
int v2 = cstr[ 1] - '0';
int val = v0 * 100 + v1 * 10 + v2;
// If valid three-digit decimal value, use it
// Note that although ascii nuls are possible in DNS labels
// we're building a C string here so we have no way to represent that
if (val == 0) val = '-';
if (val <= 255) { c = (char)val; cstr += 2; }
}
}
*ptr++ = c;
if (ptr >= label+64) { label[63] = 0; return(NULL); } // Illegal label more than 63 bytes
}
*ptr = 0; // Null-terminate label text
if (ptr == label) return(NULL); // Illegal empty label
if (*cstr) cstr++; // Skip over the trailing dot (if present)
return(cstr);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2012 Apple Inc. All rights reserved.
*
* dnsctl.c
* Command-line tool using libdns_services.dylib
*
* To build only this tool, copy and paste the following on the command line:
* On Apple 64bit Platforms ONLY OSX/iOS:
* clang -Wall dnsctl.c /usr/lib/libdns_services.dylib -o dnsctl
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <net/if.h> // if_nametoindex()
#include <dispatch/dispatch.h>
#include "dns_services.h"
//*************************************************************************************************************
// Globals:
//*************************************************************************************************************
static const char kFilePathSep = '/';
static DNSXConnRef ClientRef = NULL;
//*************************************************************************************************************
// Utility Funcs:
//*************************************************************************************************************
static void printtimestamp(void)
{
struct tm tm;
int ms;
static char date[16];
static char new_date[16];
struct timeval tv;
gettimeofday(&tv, NULL);
localtime_r((time_t*)&tv.tv_sec, &tm);
ms = tv.tv_usec/1000;
strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
//display date only if it has changed
if (strncmp(date, new_date, sizeof(new_date)))
{
printf("DATE: ---%s---\n", new_date);
strncpy(date, new_date, sizeof(date));
}
printf("%2d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
}
static void print_usage(const char *arg0)
{
fprintf(stderr, "%s USAGE: \n", arg0);
fprintf(stderr, "%s -DP Enable DNS Proxy with Default Parameters \n", arg0);
fprintf(stderr, "%s -DP [-o <output interface>] [-i <input interface(s)>] Enable DNS Proxy \n", arg0);
}
//*************************************************************************************************************
// CallBack Funcs:
//*************************************************************************************************************
// DNSXEnableProxy Callback from the Daemon
static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode)
{
(void) connRef;
printtimestamp();
switch (errCode)
{
case kDNSX_NoError : printf(" SUCCESS \n"); break;
case kDNSX_DictError : printf(" DICT ERROR \n"); break;
case kDNSX_DaemonNotRunning : printf(" NO DAEMON \n");
DNSXRefDeAlloc(ClientRef); break;
case kDNSX_Engaged : printf(" ENGAGED \n");
DNSXRefDeAlloc(ClientRef); break;
case kDNSX_UnknownErr :
default : printf("UNKNOWN ERR \n");
DNSXRefDeAlloc(ClientRef); break;
}
fflush(NULL);
}
//*************************************************************************************************************
int main(int argc, char **argv)
{
DNSXErrorType err;
// Default i/p intf is lo0 and o/p intf is primary interface
IfIndex Ipintfs[MaxInputIf] = {1, 0, 0, 0, 0};
IfIndex Opintf = kDNSIfindexAny;
// Extract program name from argv[0], which by convention contains the path to this executable
const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
if (a0 == (const char *)1)
a0 = argv[0];
// Must run as root
if (0 != geteuid())
{
fprintf(stderr, "%s MUST run as root!!\n", a0);
exit(-1);
}
if ((sizeof(argv) == 8))
printf("dnsctl running in 64-bit mode\n");
else if ((sizeof(argv) == 4))
printf("dnsctl running in 32-bit mode\n");
// expects atleast one argument
if (argc < 2)
goto Usage;
if ( !strcmp(argv[1], "-DP") || !strcmp(argv[1], "-dp") )
{
if (argc == 2)
{
printtimestamp();
printf("Proceeding to Enable DNSProxy on mDNSResponder with Default Parameters\n");
dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
}
else if (argc > 2)
{
argc--;
argv++;
if (!strcmp(argv[1], "-o"))
{
Opintf = if_nametoindex(argv[2]);
if (!Opintf)
Opintf = atoi(argv[2]);
if (!Opintf)
{
fprintf(stderr, "Could not parse o/p interface [%s]: Passing default primary \n", argv[2]);
Opintf = kDNSIfindexAny;
}
argc -= 2;
argv += 2;
}
if (argc > 2 && !strcmp(argv[1], "-i"))
{
int i;
argc--;
argv++;
for (i = 0; i < MaxInputIf && argc > 1; i++)
{
Ipintfs[i] = if_nametoindex(argv[1]);
if (!Ipintfs[i])
Ipintfs[i] = atoi(argv[1]);
if (!Ipintfs[i])
{
fprintf(stderr, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv[2]);
Ipintfs[i] = 1;
}
argc--;
argv++;
}
}
printtimestamp();
printf("Proceeding to Enable DNSProxy on mDNSResponder \n");
dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
}
}
else
{
goto Usage;
}
dispatch_main();
Usage:
print_usage(a0);
return 0;
}

View File

@ -0,0 +1,280 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// ***************************************************************************
// CryptoAlg.c:
// Interface to DNSSEC cryptographic algorithms. The crypto support itself is
// provided by the platform and the functions in this file just provide an
// interface to access them in a more generic way.
// ***************************************************************************
#include "mDNSEmbeddedAPI.h"
#include "CryptoAlg.h"
AlgFuncs *DigestAlgFuncs[DIGEST_TYPE_MAX];
AlgFuncs *CryptoAlgFuncs[CRYPTO_ALG_MAX];
AlgFuncs *EncAlgFuncs[ENC_ALG_MAX];
mDNSexport mStatus DigestAlgInit(mDNSu8 digestType, AlgFuncs *func)
{
if (digestType >= DIGEST_TYPE_MAX)
{
LogMsg("DigestAlgInit: digestType %d exceeds bounds", digestType);
return mStatus_BadParamErr;
}
// As digestTypes may not be consecutive, check for specific digest types
// that we support
if (digestType != SHA1_DIGEST_TYPE &&
digestType != SHA256_DIGEST_TYPE)
{
LogMsg("DigestAlgInit: digestType %d not supported", digestType);
return mStatus_BadParamErr;
}
DigestAlgFuncs[digestType] = func;
return mStatus_NoError;
}
mDNSexport mStatus CryptoAlgInit(mDNSu8 alg, AlgFuncs *func)
{
if (alg >= CRYPTO_ALG_MAX)
{
LogMsg("CryptoAlgInit: alg %d exceeds bounds", alg);
return mStatus_BadParamErr;
}
// As algs may not be consecutive, check for specific algorithms
// that we support
if (alg != CRYPTO_RSA_SHA1 && alg != CRYPTO_RSA_SHA256 && alg != CRYPTO_RSA_SHA512 &&
alg != CRYPTO_DSA_NSEC3_SHA1 && alg != CRYPTO_RSA_NSEC3_SHA1)
{
LogMsg("CryptoAlgInit: alg %d not supported", alg);
return mStatus_BadParamErr;
}
CryptoAlgFuncs[alg] = func;
return mStatus_NoError;
}
mDNSexport mStatus EncAlgInit(mDNSu8 alg, AlgFuncs *func)
{
if (alg >= ENC_ALG_MAX)
{
LogMsg("EncAlgInit: alg %d exceeds bounds", alg);
return mStatus_BadParamErr;
}
// As algs may not be consecutive, check for specific algorithms
// that we support
if (alg != ENC_BASE32 && alg != ENC_BASE64)
{
LogMsg("EncAlgInit: alg %d not supported", alg);
return mStatus_BadParamErr;
}
EncAlgFuncs[alg] = func;
return mStatus_NoError;
}
mDNSexport AlgContext *AlgCreate(AlgType type, mDNSu8 alg)
{
AlgFuncs *func = mDNSNULL;
AlgContext *ctx;
if (type == CRYPTO_ALG)
{
if (alg >= CRYPTO_ALG_MAX) return mDNSNULL;
func = CryptoAlgFuncs[alg];
}
else if (type == DIGEST_ALG)
{
if (alg >= DIGEST_TYPE_MAX) return mDNSNULL;
func = DigestAlgFuncs[alg];
}
else if (type == ENC_ALG)
{
if (alg >= ENC_ALG_MAX) return mDNSNULL;
func = EncAlgFuncs[alg];
}
if (!func)
{
// If there is no support from the platform, this case can happen.
LogInfo("AlgCreate: func is NULL");
return mDNSNULL;
}
if (func->Create)
{
mStatus err;
ctx = mDNSPlatformMemAllocate(sizeof(AlgContext));
if (!ctx) return mDNSNULL;
// Create expects ctx->alg to be initialized
ctx->alg = alg;
err = func->Create(ctx);
if (err == mStatus_NoError)
{
ctx->type = type;
return ctx;
}
mDNSPlatformMemFree(ctx);
}
return mDNSNULL;
}
mDNSexport mStatus AlgDestroy(AlgContext *ctx)
{
AlgFuncs *func = mDNSNULL;
if (ctx->type == CRYPTO_ALG)
func = CryptoAlgFuncs[ctx->alg];
else if (ctx->type == DIGEST_ALG)
func = DigestAlgFuncs[ctx->alg];
else if (ctx->type == ENC_ALG)
func = EncAlgFuncs[ctx->alg];
if (!func)
{
LogMsg("AlgDestroy: ERROR!! func is NULL");
mDNSPlatformMemFree(ctx);
return mStatus_BadParamErr;
}
if (func->Destroy)
func->Destroy(ctx);
mDNSPlatformMemFree(ctx);
return mStatus_NoError;
}
mDNSexport mDNSu32 AlgLength(AlgContext *ctx)
{
AlgFuncs *func = mDNSNULL;
if (ctx->type == CRYPTO_ALG)
func = CryptoAlgFuncs[ctx->alg];
else if (ctx->type == DIGEST_ALG)
func = DigestAlgFuncs[ctx->alg];
else if (ctx->type == ENC_ALG)
func = EncAlgFuncs[ctx->alg];
// This should never happen as AlgCreate would have failed
if (!func)
{
LogMsg("AlgLength: ERROR!! func is NULL");
return 0;
}
if (func->Length)
return (func->Length(ctx));
else
return 0;
}
mDNSexport mStatus AlgAdd(AlgContext *ctx, const void *data, mDNSu32 len)
{
AlgFuncs *func = mDNSNULL;
if (ctx->type == CRYPTO_ALG)
func = CryptoAlgFuncs[ctx->alg];
else if (ctx->type == DIGEST_ALG)
func = DigestAlgFuncs[ctx->alg];
else if (ctx->type == ENC_ALG)
func = EncAlgFuncs[ctx->alg];
// This should never happen as AlgCreate would have failed
if (!func)
{
LogMsg("AlgAdd: ERROR!! func is NULL");
return mStatus_BadParamErr;
}
if (func->Add)
return (func->Add(ctx, data, len));
else
return mStatus_BadParamErr;
}
mDNSexport mStatus AlgVerify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen)
{
AlgFuncs *func = mDNSNULL;
if (ctx->type == CRYPTO_ALG)
func = CryptoAlgFuncs[ctx->alg];
else if (ctx->type == DIGEST_ALG)
func = DigestAlgFuncs[ctx->alg];
else if (ctx->type == ENC_ALG)
func = EncAlgFuncs[ctx->alg];
// This should never happen as AlgCreate would have failed
if (!func)
{
LogMsg("AlgVerify: ERROR!! func is NULL");
return mStatus_BadParamErr;
}
if (func->Verify)
return (func->Verify(ctx, key, keylen, signature, siglen));
else
return mStatus_BadParamErr;
}
mDNSexport mDNSu8* AlgEncode(AlgContext *ctx)
{
AlgFuncs *func = mDNSNULL;
if (ctx->type == CRYPTO_ALG)
func = CryptoAlgFuncs[ctx->alg];
else if (ctx->type == DIGEST_ALG)
func = DigestAlgFuncs[ctx->alg];
else if (ctx->type == ENC_ALG)
func = EncAlgFuncs[ctx->alg];
// This should never happen as AlgCreate would have failed
if (!func)
{
LogMsg("AlgEncode: ERROR!! func is NULL");
return mDNSNULL;
}
if (func->Encode)
return (func->Encode(ctx));
else
return mDNSNULL;
}
mDNSexport mStatus AlgFinal(AlgContext *ctx, void *data, mDNSu32 len)
{
AlgFuncs *func = mDNSNULL;
if (ctx->type == CRYPTO_ALG)
func = CryptoAlgFuncs[ctx->alg];
else if (ctx->type == DIGEST_ALG)
func = DigestAlgFuncs[ctx->alg];
else if (ctx->type == ENC_ALG)
func = EncAlgFuncs[ctx->alg];
// This should never happen as AlgCreate would have failed
if (!func)
{
LogMsg("AlgEncode: ERROR!! func is NULL");
return mDNSNULL;
}
if (func->Final)
return (func->Final(ctx, data, len));
else
return mStatus_BadParamErr;
}

View File

@ -0,0 +1,61 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CRYPTO_ALG_H
#define __CRYPTO_ALG_H
typedef enum
{
CRYPTO_ALG,
DIGEST_ALG,
ENC_ALG,
} AlgType;
typedef struct
{
void *context;
AlgType type;
mDNSu8 alg;
} AlgContext;
typedef struct
{
mStatus (*Create)(AlgContext *ctx);
mStatus (*Destroy)(AlgContext *ctx);
mDNSu32 (*Length)(AlgContext *ctx);
mStatus (*Add)(AlgContext *ctx, const void *data, mDNSu32 len);
// Verify the ctx using the key and compare it against signature/siglen
mStatus (*Verify)(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen);
// Encode the data and return the encoded data
mDNSu8* (*Encode)(AlgContext *ctx);
// Return the finalized data in data whose length is len (used by hash algorithms)
mStatus (*Final)(AlgContext *ctx, void *data, mDNSu32 len);
} AlgFuncs;
mDNSexport mStatus DigestAlgInit(mDNSu8 digestType, AlgFuncs *func);
mDNSexport mStatus CryptoAlgInit(mDNSu8 algType, AlgFuncs *func);
mDNSexport mStatus EncAlgInit(mDNSu8 algType, AlgFuncs *func);
extern AlgContext *AlgCreate(AlgType type, mDNSu8 alg);
extern mStatus AlgDestroy(AlgContext *ctx);
extern mDNSu32 AlgLength(AlgContext *ctx);
extern mStatus AlgAdd(AlgContext *ctx, const void *data, mDNSu32 len);
extern mStatus AlgVerify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen);
extern mDNSu8* AlgEncode(AlgContext *ctx);
extern mStatus AlgFinal(AlgContext *ctx, void *data, mDNSu32 len);
#endif // __CRYPTO_ALG_H

File diff suppressed because it is too large Load Diff

View File

@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -20,8 +20,8 @@
#include "mDNSEmbeddedAPI.h"
#ifdef __cplusplus
extern "C" {
#ifdef __cplusplus
extern "C" {
#endif
//*************************************************************************************************************
@ -30,7 +30,7 @@
// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
// To expand "version" to its value before making the string, use STRINGIFY(version) instead
#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
// ***************************************************************************
@ -39,50 +39,50 @@
#endif
typedef enum
{
kDNSFlag0_QR_Mask = 0x80, // Query or response?
kDNSFlag0_QR_Query = 0x00,
kDNSFlag0_QR_Response = 0x80,
{
kDNSFlag0_QR_Mask = 0x80, // Query or response?
kDNSFlag0_QR_Query = 0x00,
kDNSFlag0_QR_Response = 0x80,
kDNSFlag0_OP_Mask = 0x78, // Operation type
kDNSFlag0_OP_StdQuery = 0x00,
kDNSFlag0_OP_Iquery = 0x08,
kDNSFlag0_OP_Status = 0x10,
kDNSFlag0_OP_Unused3 = 0x18,
kDNSFlag0_OP_Notify = 0x20,
kDNSFlag0_OP_Update = 0x28,
kDNSFlag0_OP_Mask = 0x78, // Operation type
kDNSFlag0_OP_StdQuery = 0x00,
kDNSFlag0_OP_Iquery = 0x08,
kDNSFlag0_OP_Status = 0x10,
kDNSFlag0_OP_Unused3 = 0x18,
kDNSFlag0_OP_Notify = 0x20,
kDNSFlag0_OP_Update = 0x28,
kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
kDNSFlag0_AA = 0x04, // Authoritative Answer?
kDNSFlag0_TC = 0x02, // Truncated?
kDNSFlag0_RD = 0x01, // Recursion Desired?
kDNSFlag1_RA = 0x80, // Recursion Available?
kDNSFlag0_AA = 0x04, // Authoritative Answer?
kDNSFlag0_TC = 0x02, // Truncated?
kDNSFlag0_RD = 0x01, // Recursion Desired?
kDNSFlag1_RA = 0x80, // Recursion Available?
kDNSFlag1_Zero = 0x40, // Reserved; must be zero
kDNSFlag1_AD = 0x20, // Authentic Data [RFC 2535]
kDNSFlag1_CD = 0x10, // Checking Disabled [RFC 2535]
kDNSFlag1_Zero = 0x40, // Reserved; must be zero
kDNSFlag1_AD = 0x20, // Authentic Data [RFC 2535]
kDNSFlag1_CD = 0x10, // Checking Disabled [RFC 2535]
kDNSFlag1_RC_Mask = 0x0F, // Response code
kDNSFlag1_RC_NoErr = 0x00,
kDNSFlag1_RC_FormErr = 0x01,
kDNSFlag1_RC_ServFail = 0x02,
kDNSFlag1_RC_NXDomain = 0x03,
kDNSFlag1_RC_NotImpl = 0x04,
kDNSFlag1_RC_Refused = 0x05,
kDNSFlag1_RC_YXDomain = 0x06,
kDNSFlag1_RC_YXRRSet = 0x07,
kDNSFlag1_RC_NXRRSet = 0x08,
kDNSFlag1_RC_NotAuth = 0x09,
kDNSFlag1_RC_NotZone = 0x0A
} DNS_Flags;
kDNSFlag1_RC_Mask = 0x0F, // Response code
kDNSFlag1_RC_NoErr = 0x00,
kDNSFlag1_RC_FormErr = 0x01,
kDNSFlag1_RC_ServFail = 0x02,
kDNSFlag1_RC_NXDomain = 0x03,
kDNSFlag1_RC_NotImpl = 0x04,
kDNSFlag1_RC_Refused = 0x05,
kDNSFlag1_RC_YXDomain = 0x06,
kDNSFlag1_RC_YXRRSet = 0x07,
kDNSFlag1_RC_NXRRSet = 0x08,
kDNSFlag1_RC_NotAuth = 0x09,
kDNSFlag1_RC_NotZone = 0x0A
} DNS_Flags;
typedef enum
{
TSIG_ErrBadSig = 16,
TSIG_ErrBadKey = 17,
TSIG_ErrBadTime = 18
} TSIG_ErrorCode;
{
TSIG_ErrBadSig = 16,
TSIG_ErrBadKey = 17,
TSIG_ErrBadTime = 18
} TSIG_ErrorCode;
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@ -93,7 +93,7 @@ typedef enum
extern NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf);
extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf);
extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from zero to max inclusive
extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from zero to max inclusive
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@ -101,6 +101,8 @@ extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from ze
#pragma mark - Domain Name Utility Functions
#endif
#define mDNSSubTypeLabel "\x04_sub"
#define mDNSIsDigit(X) ((X) >= '0' && (X) <= '9')
#define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z')
#define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z')
@ -139,25 +141,26 @@ extern void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBo
// (99% of the time) and then bail out before we waste time on the expensive SameDomainName() check.
#define IdenticalResourceRecord(r1,r2) ( \
(r1)->rrtype == (r2)->rrtype && \
(r1)->rrclass == (r2)->rrclass && \
(r1)->namehash == (r2)->namehash && \
(r1)->rdlength == (r2)->rdlength && \
(r1)->rdatahash == (r2)->rdatahash && \
SameRDataBody((r1), &(r2)->rdata->u, SameDomainName) && \
SameDomainName((r1)->name, (r2)->name))
(r1)->rrtype == (r2)->rrtype && \
(r1)->rrclass == (r2)->rrclass && \
(r1)->namehash == (r2)->namehash && \
(r1)->rdlength == (r2)->rdlength && \
(r1)->rdatahash == (r2)->rdatahash && \
SameRDataBody((r1), &(r2)->rdata->u, SameDomainName) && \
SameDomainName((r1)->name, (r2)->name))
#define IdenticalSameNameRecord(r1,r2) ( \
(r1)->rrtype == (r2)->rrtype && \
(r1)->rrclass == (r2)->rrclass && \
(r1)->rdlength == (r2)->rdlength && \
(r1)->rdatahash == (r2)->rdatahash && \
SameRDataBody((r1), &(r2)->rdata->u, SameDomainName))
(r1)->rrtype == (r2)->rrtype && \
(r1)->rrclass == (r2)->rrclass && \
(r1)->rdlength == (r2)->rdlength && \
(r1)->rdatahash == (r2)->rdatahash && \
SameRDataBody((r1), &(r2)->rdata->u, SameDomainName))
// A given RRType answers a QuestionType if RRType is CNAME, or types match, or QuestionType is ANY,
// or the RRType is NSEC and positively asserts the nonexistence of the type being requested
#define RRTypeAnswersQuestionType(R,Q) ((R)->rrtype == kDNSType_CNAME || (R)->rrtype == (Q) || (Q) == kDNSQType_ANY || RRAssertsNonexistence((R),(Q)))
#define RRAssertsNonexistence(R,T) ((R)->rrtype == kDNSType_NSEC && (T) < kDNSQType_ANY && !((R)->rdata->u.nsec.bitmap[(T)>>3] & (128 >> ((T)&7))))
// Unicast NSEC records have the NSEC bit set whereas the multicast NSEC ones don't
#define UNICAST_NSEC(rr) ((rr)->rrtype == kDNSType_NSEC && RRAssertsExistence((rr), kDNSType_NSEC))
extern mDNSu32 RDataHashValue(const ResourceRecord *const rr);
extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename);
@ -168,11 +171,12 @@ extern mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const
extern mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const rr, const DNSQuestion *const q);
extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
extern mStatus DNSNameToLowerCase(domainname *d, domainname *result);
#define GetRRDomainNameTarget(RR) ( \
((RR)->rrtype == kDNSType_NS || (RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_DNAME) ? &(RR)->rdata->u.name : \
((RR)->rrtype == kDNSType_MX || (RR)->rrtype == kDNSType_AFSDB || (RR)->rrtype == kDNSType_RT || (RR)->rrtype == kDNSType_KX ) ? &(RR)->rdata->u.mx.exchange : \
((RR)->rrtype == kDNSType_SRV ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
((RR)->rrtype == kDNSType_NS || (RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_DNAME) ? &(RR)->rdata->u.name : \
((RR)->rrtype == kDNSType_MX || (RR)->rrtype == kDNSType_AFSDB || (RR)->rrtype == kDNSType_RT || (RR)->rrtype == kDNSType_KX ) ? &(RR)->rdata->u.mx.exchange : \
((RR)->rrtype == kDNSType_SRV ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
#define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique)
@ -195,17 +199,17 @@ extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *
extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit);
#define PutResourceRecordTTL(msg, ptr, count, rr, ttl) \
PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AllowedRRSpace(msg))
PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AllowedRRSpace(msg))
#define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) \
PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AbsoluteMaxDNSMessageData)
PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AbsoluteMaxDNSMessageData)
#define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
// The PutRR_OS variants assume a local variable 'm', put build the packet at m->omsg,
// and assume a local variable 'OwnerRecordSpace' indicating how many bytes (if any) to reserve to add an OWNER option at the end
// and assume local variables 'OwnerRecordSpace' & 'TraceRecordSpace' indicating how many bytes (if any) to reserve to add an OWNER/TRACER option at the end
#define PutRR_OS_TTL(ptr, count, rr, ttl) \
PutResourceRecordTTLWithLimit(&m->omsg, (ptr), (count), (rr), (ttl), m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace)
PutResourceRecordTTLWithLimit(&m->omsg, (ptr), (count), (rr), (ttl), m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace)
#define PutRR_OS(P, C, RR) PutRR_OS_TTL((P), (C), (RR), (RR)->rroriginalttl)
@ -220,6 +224,12 @@ extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease);
extern mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit);
extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *ptr, DomainAuthInfo *authInfo, mDNSu8 *limit);
extern mDNSu8 *putDNSSECOption(DNSMessage *msg, mDNSu8 *end, mDNSu8 *limit);
extern int baseEncode(char *buffer, int blen, const mDNSu8 *data, int len, int encAlg);
extern void NSEC3Parse(const ResourceRecord *const rr, mDNSu8 **salt, int *hashLength, mDNSu8 **nxtName, int *bitmaplen, mDNSu8 **bitmap);
extern const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 *AnonData, int AnonDataLen,
const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@ -233,13 +243,15 @@ extern mDNSu32 DomainNameHashValue(const domainname *const name);
extern void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength);
extern const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end);
extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
domainname *const name);
domainname *const name);
extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr);
const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr);
extern mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end,
LargeCacheRecord *const largecr, mDNSu16 rdlength);
extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
DNSQuestion *question);
DNSQuestion *question);
extern const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end);
extern const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end);
extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end);
@ -247,8 +259,14 @@ extern const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *cons
extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end);
extern mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end);
extern void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport,
const mDNSAddr *srcaddr, mDNSIPPort srcport,
const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end);
const mDNSAddr *srcaddr, mDNSIPPort srcport,
const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end);
extern mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type);
extern mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type);
extern mDNSBool BitmapTypeCheck(mDNSu8 *bmap, int bitmaplen, mDNSu16 type);
extern mDNSu16 swap16(mDNSu16 x);
extern mDNSu32 swap32(mDNSu32 x);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@ -257,7 +275,9 @@ extern void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *trans
#endif
extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo);
mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
mDNSBool useBackgroundTrafficClass);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@ -277,16 +297,19 @@ extern void mDNS_Unlock_(mDNS *const m, const char * const functionname);
#define mDNS_Unlock(X) mDNS_Unlock_((X), __func__)
#define mDNS_CheckLock(X) { if ((X)->mDNS_busy != (X)->mDNS_reentrancy+1) \
LogMsg("%s: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); }
#define mDNS_DropLockBeforeCallback() do { m->mDNS_reentrancy++; \
if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Locking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
} while (0)
if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Locking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
} while (0)
#define mDNS_ReclaimLockAfterCallback() do { \
if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Unlocking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
m->mDNS_reentrancy--; } while (0)
if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Unlocking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
m->mDNS_reentrancy--; } while (0)
#ifdef __cplusplus
}
#ifdef __cplusplus
}
#endif
#endif // __DNSCOMMON_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,597 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mDNSEmbeddedAPI.h"
#include "CryptoAlg.h"
#include "anonymous.h"
#include "DNSCommon.h"
// Define ANONYMOUS_DISABLED to remove all the anonymous functionality
// and use the stub functions implemented later in this file.
#ifndef ANONYMOUS_DISABLED
#define ANON_NSEC3_ITERATIONS 1
mDNSlocal mDNSBool InitializeNSEC3Record(ResourceRecord *rr, const mDNSu8 *AnonData, int len, mDNSu32 salt)
{
const mDNSu8 *ptr;
rdataNSEC3 *nsec3 = (rdataNSEC3 *)rr->rdata->u.data;
mDNSu8 *tmp, *nxt;
unsigned short iter = ANON_NSEC3_ITERATIONS;
int hlen;
const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
// Construct the RDATA first and construct the owner name based on that.
ptr = (const mDNSu8 *)&salt;
debugf("InitializeNSEC3Record: %x%x%x%x, name %##s", ptr[0], ptr[1], ptr[2], ptr[3], rr->name->c);
// Set the RDATA
nsec3->alg = SHA1_DIGEST_TYPE;
nsec3->flags = 0;
nsec3->iterations = swap16(iter);
nsec3->saltLength = 4;
tmp = (mDNSu8 *)&nsec3->salt;
*tmp++ = ptr[0];
*tmp++ = ptr[1];
*tmp++ = ptr[2];
*tmp++ = ptr[3];
// hashLength, nxt, bitmap
*tmp++ = SHA1_HASH_LENGTH; // hash length
nxt = tmp;
tmp += SHA1_HASH_LENGTH;
*tmp++ = 0; // window number
*tmp++ = NSEC_MCAST_WINDOW_SIZE; // window length
mDNSPlatformMemZero(tmp, NSEC_MCAST_WINDOW_SIZE);
tmp[kDNSType_PTR >> 3] |= 128 >> (kDNSType_PTR & 7);
// Hash the base service name + salt + AnonData
if (!NSEC3HashName(rr->name, nsec3, AnonData, len, hashName, &hlen))
{
LogMsg("InitializeNSEC3Record: NSEC3HashName failed for ##s", rr->name->c);
return mDNSfalse;
}
if (hlen != SHA1_HASH_LENGTH)
{
LogMsg("InitializeNSEC3Record: hlen wrong %d", hlen);
return mDNSfalse;
}
mDNSPlatformMemCopy(nxt, hashName, hlen);
return mDNStrue;
}
mDNSlocal ResourceRecord *ConstructNSEC3Record(const domainname *service, const mDNSu8 *AnonData, int len, mDNSu32 salt)
{
ResourceRecord *rr;
int dlen;
domainname *name;
// We are just allocating an RData which has StandardAuthRDSize
if (StandardAuthRDSize < MCAST_NSEC3_RDLENGTH)
{
LogMsg("ConstructNSEC3Record: StandardAuthRDSize %d smaller than MCAST_NSEC3_RDLENGTH %d", StandardAuthRDSize, MCAST_NSEC3_RDLENGTH);
return mDNSNULL;
}
dlen = DomainNameLength(service);
// Allocate space for the name and RData.
rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + dlen + sizeof(RData));
if (!rr)
return mDNSNULL;
name = (domainname *)((mDNSu8 *)rr + sizeof(ResourceRecord));
rr->RecordType = kDNSRecordTypePacketAuth;
rr->InterfaceID = mDNSInterface_Any;
rr->name = (const domainname *)name;
rr->rrtype = kDNSType_NSEC3;
rr->rrclass = kDNSClass_IN;
rr->rroriginalttl = kStandardTTL;
rr->rDNSServer = mDNSNULL;
rr->rdlength = MCAST_NSEC3_RDLENGTH;
rr->rdestimate = MCAST_NSEC3_RDLENGTH;
rr->rdata = (RData *)((mDNSu8 *)rr->name + dlen);
AssignDomainName(name, service);
if (!InitializeNSEC3Record(rr, AnonData, len, salt))
{
mDNSPlatformMemFree(rr);
return mDNSNULL;
}
return rr;
}
mDNSlocal ResourceRecord *CopyNSEC3ResourceRecord(AnonymousInfo *si, const ResourceRecord *rr)
{
int len;
domainname *name;
ResourceRecord *nsec3rr;
if (rr->rdlength < MCAST_NSEC3_RDLENGTH)
{
LogMsg("CopyNSEC3ResourceRecord: rdlength %d smaller than MCAST_NSEC3_RDLENGTH %d", rr->rdlength, MCAST_NSEC3_RDLENGTH);
return mDNSNULL;
}
// Allocate space for the name and the rdata along with the ResourceRecord
len = DomainNameLength(rr->name);
nsec3rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + len + sizeof(RData));
if (!nsec3rr)
return mDNSNULL;
*nsec3rr = *rr;
name = (domainname *)((mDNSu8 *)nsec3rr + sizeof(ResourceRecord));
nsec3rr->name = (const domainname *)name;
AssignDomainName(name, rr->name);
nsec3rr->rdata = (RData *)((mDNSu8 *)nsec3rr->name + len);
mDNSPlatformMemCopy(nsec3rr->rdata->u.data, rr->rdata->u.data, rr->rdlength);
si->nsec3RR = nsec3rr;
return nsec3rr;
}
// When a service is started or a browse is started with the Anonymous data, we allocate a new random
// number and based on that allocate a new NSEC3 resource record whose hash is a function of random number (salt) and
// the anonymous data.
//
// If we receive a packet with the NSEC3 option, we need to cache that along with the resource record so that we can
// check against the question to see whether it answers them or not. In that case, we pass the "rr" that we received.
mDNSexport AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *data, int len, const ResourceRecord *rr)
{
AnonymousInfo *ai;
ai = (AnonymousInfo *)mDNSPlatformMemAllocate(sizeof(AnonymousInfo));
if (!ai)
{
return mDNSNULL;
}
mDNSPlatformMemZero(ai, sizeof(AnonymousInfo));
if (rr)
{
if (!CopyNSEC3ResourceRecord(ai, rr))
{
mDNSPlatformMemFree(ai);
return mDNSNULL;
}
return ai;
}
ai->salt = mDNSRandom(0xFFFFFFFF);
ai->AnonData = mDNSPlatformMemAllocate(len);
if (!ai->AnonData)
{
mDNSPlatformMemFree(ai);
return mDNSNULL;
}
ai->AnonDataLen = len;
mDNSPlatformMemCopy(ai->AnonData, data, len);
ai->nsec3RR = ConstructNSEC3Record(service, data, len, ai->salt);
if (!ai->nsec3RR)
{
mDNSPlatformMemFree(ai);
return mDNSNULL;
}
return ai;
}
mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
{
if (ai->nsec3RR)
mDNSPlatformMemFree(ai->nsec3RR);
if (ai->AnonData)
mDNSPlatformMemFree(ai->AnonData);
mDNSPlatformMemFree(ai);
}
mDNSexport void ReInitAnonInfo(AnonymousInfo **AnonInfo, const domainname *name)
{
if (*AnonInfo)
{
AnonymousInfo *ai = *AnonInfo;
*AnonInfo = AllocateAnonInfo(name, ai->AnonData, ai->AnonDataLen, mDNSNULL);
if (!(*AnonInfo))
*AnonInfo = ai;
else
FreeAnonInfo(ai);
}
}
// This function should be used only if you know that the question and
// the resource record belongs to the same set. The main usage is
// in ProcessQuery where we find the question to be part of the same
// set as the resource record, but it needs the AnonData to be
// initialized so that it can walk the cache records to see if they
// answer the question.
mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
{
if (!q->AnonInfo || !rr->AnonInfo)
{
LogMsg("SetAnonData: question %##s(%p), rr %##s(%p), NULL", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
return;
}
debugf("SetAnonData: question %##s(%p), rr %##s(%p)", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
if (ForQuestion)
{
if (!q->AnonInfo->AnonData)
{
q->AnonInfo->AnonData = mDNSPlatformMemAllocate(rr->AnonInfo->AnonDataLen);
if (!q->AnonInfo->AnonData)
return;
}
mDNSPlatformMemCopy(q->AnonInfo->AnonData, rr->AnonInfo->AnonData, rr->AnonInfo->AnonDataLen);
q->AnonInfo->AnonDataLen = rr->AnonInfo->AnonDataLen;
}
else
{
if (!rr->AnonInfo->AnonData)
{
rr->AnonInfo->AnonData = mDNSPlatformMemAllocate(q->AnonInfo->AnonDataLen);
if (!rr->AnonInfo->AnonData)
return;
}
mDNSPlatformMemCopy(rr->AnonInfo->AnonData, q->AnonInfo->AnonData, q->AnonInfo->AnonDataLen);
rr->AnonInfo->AnonDataLen = q->AnonInfo->AnonDataLen;
}
}
// returns -1 if the caller should ignore the result
// returns 1 if the record answers the question
// returns 0 if the record does not answer the question
mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
{
mDNSexport mDNS mDNSStorage;
ResourceRecord *nsec3RR;
int i;
AnonymousInfo *qai, *rai;
mDNSu8 *AnonData;
int AnonDataLen;
rdataNSEC3 *nsec3;
int hlen;
const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
int nxtLength;
mDNSu8 *nxtName;
debugf("AnonInfoAnswersQuestion: question qname %##s", q->qname.c);
// Currently only PTR records can have anonymous information
if (q->qtype != kDNSType_PTR)
{
return -1;
}
// We allow anonymous questions to be answered by both normal services (without the
// anonymous information) and anonymous services that are part of the same set. And
// normal questions discover normal services and all anonymous services.
//
// The three cases have been enumerated clearly even though they all behave the
// same way.
if (!q->AnonInfo)
{
debugf("AnonInfoAnswersQuestion: not a anonymous type question");
if (!rr->AnonInfo)
{
// case 1
return -1;
}
else
{
// case 2
debugf("AnonInfoAnswersQuestion: Question %##s not answered using anonymous record %##s", q->qname.c, rr->name->c);
return -1;
}
}
else
{
// case 3
if (!rr->AnonInfo)
{
debugf("AnonInfoAnswersQuestion: not a anonymous type record");
return -1;
}
}
// case 4: We have the anonymous information both in the question and the record. We need
// two sets of information to validate.
//
// 1) Anonymous data that identifies the set/group
// 2) NSEC3 record that contains the hash and the salt
//
// If the question is a remote one, it does not have the anonymous information to validate (just
// the NSEC3 record) and hence the anonymous data should come from the local resource record. If the
// question is local, it can come from either of them and if there is a mismatch between the
// question and record, it won't validate.
qai = q->AnonInfo;
rai = rr->AnonInfo;
if (qai->AnonData && rai->AnonData)
{
// Before a cache record is created, if there is a matching question i.e., part
// of the same set, then when the cache is created we also set the anonymous
// information. Otherwise, the cache record contains just the NSEC3 record and we
// won't be here for that case.
//
// It is also possible that a local question is matched against the local AuthRecord
// as that is also the case for which the AnonData would be non-NULL for both.
// We match questions against AuthRecords (rather than the cache) for LocalOnly case and
// to see whether a .local query should be suppressed or not. The latter never happens
// because PTR queries are never suppressed.
// If they don't belong to the same anonymous set, then no point in validating.
if ((qai->AnonDataLen != rai->AnonDataLen) ||
mDNSPlatformMemCmp(qai->AnonData, rai->AnonData, qai->AnonDataLen) != 0)
{
debugf("AnonInfoAnswersQuestion: AnonData mis-match for record %s question %##s ",
RRDisplayString(&mDNSStorage, rr), q->qname.c);
return 0;
}
// AnonData matches i.e they belong to the same group and the same service.
LogInfo("AnonInfoAnswersQuestion: Answering qname %##s, rname %##s, without validation", q->qname.c,
rr->name->c);
return 1;
}
else
{
debugf("AnonInfoAnswersQuestion: question %p, record %p", qai->AnonData, rai->AnonData);
}
if (qai->AnonData)
{
// If there is AnonData, then this is a local question. The
// NSEC3 RR comes from the resource record which could be part
// of the cache or local auth record. The cache entry could
// be from a remote host or created when we heard our own
// announcements. In any case, we use that to see if it matches
// the question.
AnonData = qai->AnonData;
AnonDataLen = qai->AnonDataLen;
nsec3RR = rai->nsec3RR;
}
else
{
// Remote question or hearing our own question back
AnonData = rai->AnonData;
AnonDataLen = rai->AnonDataLen;
nsec3RR = qai->nsec3RR;
}
if (!AnonData || !nsec3RR)
{
// AnonData can be NULL for the cache entry and if we are hearing our own question back, AnonData is NULL for
// that too and we can end up here for that case.
debugf("AnonInfoAnswersQuestion: AnonData %p or nsec3RR %p, NULL for question %##s, record %s", AnonData, nsec3RR,
q->qname.c, RRDisplayString(&mDNSStorage, rr));
return 0;
}
debugf("AnonInfoAnswersQuestion: Validating question %##s, ResourceRecord %s", q->qname.c, RRDisplayString(&mDNSStorage, nsec3RR));
nsec3 = (rdataNSEC3 *)nsec3RR->rdata->u.data;
if (!NSEC3HashName(nsec3RR->name, nsec3, AnonData, AnonDataLen, hashName, &hlen))
{
LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for ##s", nsec3RR->name->c);
return mDNSfalse;
}
if (hlen != SHA1_HASH_LENGTH)
{
LogMsg("AnonInfoAnswersQuestion: hlen wrong %d", hlen);
return mDNSfalse;
}
NSEC3Parse(nsec3RR, mDNSNULL, &nxtLength, &nxtName, mDNSNULL, mDNSNULL);
if (hlen != nxtLength)
{
LogMsg("AnonInfoAnswersQuestion: ERROR!! hlen %d not same as nxtLength %d", hlen, nxtLength);
return mDNSfalse;
}
for (i = 0; i < nxtLength; i++)
{
if (nxtName[i] != hashName[i])
{
debugf("AnonInfoAnswersQuestion: mismatch output %x, digest %x, i %d", nxtName[i+1], hashName[i], i);
return 0;
}
}
LogInfo("AnonInfoAnswersQuestion: ResourceRecord %s matched question %##s (%s)", RRDisplayString(&mDNSStorage, nsec3RR), q->qname.c, DNSTypeName(q->qtype));
return 1;
}
// Find a matching NSEC3 record for the name. We parse the questions and the records in the packet in order.
// Similarly we also parse the NSEC3 records in order and this mapping to the questions and records
// respectively.
mDNSlocal CacheRecord *FindMatchingNSEC3ForName(mDNS *const m, CacheRecord **nsec3, const domainname *name)
{
CacheRecord *cr;
CacheRecord **prev = nsec3;
(void) m;
for (cr = *nsec3; cr; cr = cr->next)
{
if (SameDomainName(cr->resrec.name, name))
{
debugf("FindMatchingNSEC3ForName: NSEC3 record %s matched %##s", CRDisplayString(m, cr), name->c);
*prev = cr->next;
cr->next = mDNSNULL;
return cr;
}
prev = &cr->next;
}
return mDNSNULL;
}
mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
{
CacheRecord *nsec3CR;
if (q->qtype != kDNSType_PTR)
return;
nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, &q->qname);
if (nsec3CR)
{
q->AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
if (q->AnonInfo)
{
debugf("InitializeAnonInfoForQuestion: Found a matching NSEC3 record %s, for %##s (%s)",
RRDisplayString(m, q->AnonInfo->nsec3RR), q->qname.c, DNSTypeName(q->qtype));
}
ReleaseCacheRecord(m, nsec3CR);
}
}
mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
{
CacheRecord *nsec3CR;
if (!(*McastNSEC3Records))
return;
// If already initialized or not a PTR type, we don't have to do anything
if (cr->resrec.AnonInfo || cr->resrec.rrtype != kDNSType_PTR)
return;
nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, cr->resrec.name);
if (nsec3CR)
{
cr->resrec.AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
if (cr->resrec.AnonInfo)
{
debugf("InitializeAnonInfoForCR: Found a matching NSEC3 record %s, for %##s (%s)",
RRDisplayString(m, cr->resrec.AnonInfo->nsec3RR), cr->resrec.name->c,
DNSTypeName(cr->resrec.rrtype));
}
ReleaseCacheRecord(m, nsec3CR);
}
}
mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
{
// if a1 is NULL and a2 is not NULL AND vice-versa
// return false as there is a change.
if ((a1 != mDNSNULL) != (a2 != mDNSNULL))
return mDNSfalse;
// Both could be NULL or non-NULL
if (a1 && a2)
{
// The caller already verified that the owner name is the same.
// Check whether the RData is same.
if (!IdenticalSameNameRecord(a1->nsec3RR, a2->nsec3RR))
{
debugf("IdenticalAnonInfo: nsec3RR mismatch");
return mDNSfalse;
}
}
return mDNStrue;
}
mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
{
AnonymousInfo *aifrom = crfrom->resrec.AnonInfo;
AnonymousInfo *aito = crto->resrec.AnonInfo;
(void) m;
if (!aifrom)
return;
if (aito)
{
crto->resrec.AnonInfo = aifrom;
FreeAnonInfo(aito);
crfrom->resrec.AnonInfo = mDNSNULL;
}
else
{
FreeAnonInfo(aifrom);
crfrom->resrec.AnonInfo = mDNSNULL;
}
}
#else // !ANONYMOUS_DISABLED
mDNSexport void ReInitAnonInfo(AnonymousInfo **si, const domainname *name)
{
(void)si;
(void)name;
}
mDNSexport AnonymousInfo * AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr)
{
(void)service;
(void)AnonData;
(void)len;
(void)rr;
return mDNSNULL;
}
mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
{
(void)ai;
}
mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
{
(void)q;
(void)rr;
(void)ForQuestion;
}
mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
{
(void)rr;
(void)q;
return mDNSfalse;
}
mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
{
(void)m;
(void)McastNSEC3Records;
(void)q;
}
mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
{
(void)m;
(void)McastNSEC3Records;
(void)cr;
}
mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
{
(void)m;
(void)crto;
(void)crfrom;
}
mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
{
(void)a1;
(void)a2;
return mDNStrue;
}
#endif // !ANONYMOUS_DISABLED

View File

@ -0,0 +1,31 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __ANONYMOUS_H_
#define __ANONYMOUS_H_
extern void ReInitAnonInfo(AnonymousInfo **si, const domainname *name);
extern AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr);
extern void FreeAnonInfo(AnonymousInfo *ai);
extern void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion);
extern int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr);
extern void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q);
extern void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom);
extern mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2);
#endif

View File

@ -0,0 +1,836 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dnsproxy.h"
#ifndef UNICAST_DISABLED
// Implementation Notes
//
// DNS Proxy listens on port 53 (UDPv4v6 & TCPv4v6) for DNS queries. It handles only
// the "Query" opcode of the DNS protocol described in RFC 1035. For all other opcodes, it returns
// "Not Implemented" error. The platform interface mDNSPlatformInitDNSProxySkts
// sets up the sockets and whenever it receives a packet, it calls ProxyTCPCallback or ProxyUDPCallback
// defined here. For TCP socket, the platform does the "accept" and only sends the received packets
// on the newly accepted socket. A single UDP socket (per address family) is used to send/recv
// requests/responses from all clients. For TCP, there is one socket per request. Hence, there is some
// extra state that needs to be disposed at the end.
//
// When a DNS request is received, ProxyCallbackCommon checks for malformed packet etc. and also checks
// for duplicates, before creating DNSProxyClient state and starting a question with the "core"
// (mDNS_StartQuery). When the callback for the question happens, it gathers all the necessary
// resource records, constructs a response and sends it back to the client.
//
// - Question callback is called with only one resource record at a time. We need all the resource
// records to construct the response. Hence, we lookup all the records ourselves.
//
// - The response may not fit the client's buffer size. In that case, we need to set the truncate bit
// and the client would retry using TCP.
//
// - The client may have set the DNSSEC OK bit in the EDNS0 option and that means we also have to
// return the RRSIGs or the NSEC records with the RRSIGs in the Additional section. We need to
// ask the "core" to fetch the DNSSEC records and do the validation if the CD bit is not set.
//
// Once the response is sent to the client, the client state is disposed. When there is no response
// from the "core", it eventually times out and we will not find any answers in the cache and we send a
// "NXDomain" response back. Thus, we don't need any special timers to reap the client state in the case
// of errors.
typedef struct DNSProxyClient_struct DNSProxyClient;
struct DNSProxyClient_struct {
DNSProxyClient *next;
mDNSAddr addr; // Client's IP address
mDNSIPPort port; // Client's port number
mDNSOpaque16 msgid; // DNS msg id
mDNSInterfaceID interfaceID; // Interface on which we received the request
void *socket; // Return socket
mDNSBool tcp; // TCP or UDP ?
mDNSOpaque16 requestFlags; // second 16 bit word in the DNSMessageHeader of the request
mDNSu8 *optRR; // EDNS0 option
mDNSu16 optLen; // Total Length of the EDNS0 option
mDNSu16 rcvBufSize; // How much can the client receive ?
mDNSBool DNSSECOK; // DNSSEC OK ?
void *context; // Platform context to be disposed if non-NULL
domainname qname; // q->qname can't be used for duplicate check
DNSQuestion q; // as it can change underneath us for CNAMEs
};
#define MIN_DNS_MESSAGE_SIZE 512
DNSProxyClient *DNSProxyClients;
mDNSlocal void FreeDNSProxyClient(DNSProxyClient *pc)
{
if (pc->optRR)
mDNSPlatformMemFree(pc->optRR);
mDNSPlatformMemFree(pc);
}
mDNSlocal mDNSBool ParseEDNS0(DNSProxyClient *pc, const mDNSu8 *ptr, int length, const mDNSu8 *limit)
{
mDNSu16 rrtype, rrclass;
mDNSu8 rcode, version;
mDNSu16 flag;
if (ptr + length > limit)
{
LogInfo("ParseEDNS0: Not enough space in the packet");
return mDNSfalse;
}
// Skip the root label
ptr++;
rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]);
if (rrtype != kDNSType_OPT)
{
LogInfo("ParseEDNS0: Not the right type %d", rrtype);
return mDNSfalse;
}
rrclass = (mDNSu16) ((mDNSu16)ptr[2] << 8 | ptr[3]);
rcode = ptr[4];
version = ptr[5];
flag = (mDNSu16) ((mDNSu16)ptr[6] << 8 | ptr[7]);
debugf("rrtype is %s, length is %d, rcode %d, version %d, flag 0x%x", DNSTypeName(rrtype), rrclass, rcode, version, flag);
pc->rcvBufSize = rrclass;
pc->DNSSECOK = ptr[6] & 0x80;
return mDNStrue;
}
mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
{
DNSProxyClient *pc = (DNSProxyClient *)q->QuestionContext;
(void) msg;
h->flags = pc->requestFlags;
if (pc->optRR)
{
if (ptr + pc->optLen > limit)
{
LogInfo("DNSProxySetAttributes: Cannot set EDNS0 option start %p, OptLen %d, end %p", ptr, pc->optLen, limit);
return ptr;
}
h->numAdditionals++;
mDNSPlatformMemCopy(ptr, pc->optRR, pc->optLen);
ptr += pc->optLen;
}
return ptr;
}
mDNSlocal mDNSu8 *AddEDNS0Option(mDNS *const m, mDNSu8 *ptr, mDNSu8 *limit)
{
int len = 4096;
if (ptr + 11 > limit)
{
LogInfo("AddEDNS0Option: not enough space");
return mDNSNULL;
}
m->omsg.h.numAdditionals++;
ptr[0] = 0;
ptr[1] = (mDNSu8) (kDNSType_OPT >> 8);
ptr[2] = (mDNSu8) (kDNSType_OPT & 0xFF);
ptr[3] = (mDNSu8) (len >> 8);
ptr[4] = (mDNSu8) (len & 0xFF);
ptr[5] = 0; // rcode
ptr[6] = 0; // version
ptr[7] = 0;
ptr[8] = 0; // flags
ptr[9] = 0; // rdlength
ptr[10] = 0; // rdlength
debugf("AddEDNS0 option");
return (ptr + 11);
}
// Currently RD and CD bit should be copied if present in the request or cleared if
// not present in the request. RD bit is normally set in the response and hence the
// cache reflects the right value. CD bit behaves differently. If the CD bit is set
// the first time, the cache retains it, if it is present in response (assuming the
// upstream server does it right). Next time through we should not use the cached
// value of the CD bit blindly. It depends on whether it was in the request or not.
mDNSlocal mDNSOpaque16 SetResponseFlags(DNSProxyClient *pc, const mDNSOpaque16 responseFlags)
{
mDNSOpaque16 rFlags = responseFlags;
if (pc->requestFlags.b[0] & kDNSFlag0_RD)
rFlags.b[0] |= kDNSFlag0_RD;
else
rFlags.b[0] &= ~kDNSFlag0_RD;
if (pc->requestFlags.b[1] & kDNSFlag1_CD)
rFlags.b[1] |= kDNSFlag1_CD;
else
rFlags.b[1] &= ~kDNSFlag1_CD;
return rFlags;
}
mDNSlocal mDNSu8 *AddResourceRecords(mDNS *const m, DNSProxyClient *pc, mDNSu8 **prevptr, mStatus *error)
{
mDNSu32 slot;
CacheGroup *cg;
CacheRecord *cr;
int len = sizeof(DNSMessageHeader);
mDNSu8 *orig = m->omsg.data;
mDNSBool first = mDNStrue;
mDNSu8 *ptr = mDNSNULL;
mDNSs32 now;
mDNSs32 ttl;
CacheRecord *nsec = mDNSNULL;
CacheRecord *soa = mDNSNULL;
CacheRecord *cname = mDNSNULL;
mDNSu8 *limit;
*error = mStatus_NoError;
*prevptr = mDNSNULL;
mDNS_Lock(m);
now = m->timenow;
mDNS_Unlock(m);
if (!pc->tcp)
{
if (!pc->rcvBufSize)
{
limit = m->omsg.data + MIN_DNS_MESSAGE_SIZE;
}
else
{
limit = (pc->rcvBufSize > AbsoluteMaxDNSMessageData ? m->omsg.data + AbsoluteMaxDNSMessageData : m->omsg.data + pc->rcvBufSize);
}
}
else
{
// For TCP, limit is not determined by EDNS0 but by 16 bit rdlength field and
// AbsoluteMaxDNSMessageData is smaller than 64k.
limit = m->omsg.data + AbsoluteMaxDNSMessageData;
}
LogInfo("AddResourceRecords: Limit is %d", limit - m->omsg.data);
if (!SameDomainName(&pc->qname, &pc->q.qname))
{
AssignDomainName(&pc->q.qname, &pc->qname);
pc->q.qnamehash = DomainNameHashValue(&pc->q.qname);
}
again:
nsec = soa = cname = mDNSNULL;
slot = HashSlot(&pc->q.qname);
cg = CacheGroupForName(m, slot, pc->q.qnamehash, &pc->q.qname);
if (!cg)
{
LogInfo("AddResourceRecords: CacheGroup not found");
*error = mStatus_NoSuchRecord;
return mDNSNULL;
}
// Set ValidatingResponse so that you can get RRSIGs also matching
// the question
if (pc->DNSSECOK)
pc->q.ValidatingResponse = 1;
for (cr = cg->members; cr; cr = cr->next)
{
if (SameNameRecordAnswersQuestion(&cr->resrec, &pc->q))
{
if (first)
{
// If this is the first time, initialize the header and the question.
// This code needs to be here so that we can use the responseFlags from the
// cache record
mDNSOpaque16 responseFlags = SetResponseFlags(pc, cr->responseFlags);
InitializeDNSMessage(&m->omsg.h, pc->msgid, responseFlags);
ptr = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &pc->qname, pc->q.qtype, pc->q.qclass);
if (!ptr)
{
LogInfo("AddResourceRecords: putQuestion NULL for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype));
return mDNSNULL;
}
first = mDNSfalse;
}
// - For NegativeAnswers there is nothing to add
// - If DNSSECOK is set, we also automatically lookup the RRSIGs which
// will also be returned. If the client is explicitly looking up
// a DNSSEC record (e.g., DNSKEY, DS) we should return the response.
// DNSSECOK bit only influences whether we add the RRSIG or not.
if (cr->resrec.RecordType != kDNSRecordTypePacketNegative)
{
LogInfo("AddResourceRecords: Answering question with %s", CRDisplayString(m, cr));
ttl = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.numAnswers, &cr->resrec, ttl, limit);
if (!ptr)
{
*prevptr = orig;
return mDNSNULL;
}
len += (ptr - orig);
orig = ptr;
}
// If we have nsecs (wildcard expanded answer or negative response), add them
// in the additional section below if the DNSSECOK bit is set
if (pc->DNSSECOK && cr->nsec)
{
LogInfo("AddResourceRecords: nsec set for %s", CRDisplayString(m ,cr));
nsec = cr->nsec;
}
if (cr->soa)
{
LogInfo("AddResourceRecords: soa set for %s", CRDisplayString(m ,cr));
soa = cr->soa;
}
// If we are using CNAME to answer a question and CNAME is not the type we
// are looking for, note down the CNAME record so that we can follow them
// later. Before we follow the CNAME, print the RRSIGs and any nsec (wildcard
// expanded) if any.
if ((pc->q.qtype != cr->resrec.rrtype) && cr->resrec.rrtype == kDNSType_CNAME)
{
LogInfo("AddResourceRecords: cname set for %s", CRDisplayString(m ,cr));
cname = cr;
}
}
}
// Along with the nsec records, we also cache the SOA record. For non-DNSSEC question, we need
// to send the SOA back. Normally we either cache the SOA record (non-DNSSEC question) pointed
// to by "cr->soa" or the NSEC/SOA records along with their RRSIGs (DNSSEC question) pointed to
// by "cr->nsec". Two cases:
//
// - if we issue a DNSSEC question followed by non-DNSSEC question for the same name,
// we only have the nsec records and we need to filter the SOA record alone for the
// non-DNSSEC questions.
//
// - if we issue a non-DNSSEC question followed by DNSSEC question for the same name,
// the "core" flushes the cache entry and re-issue the question with EDNS0/DOK bit and
// in this case we return all the DNSSEC records we have.
for (; nsec; nsec = nsec->next)
{
if (!pc->DNSSECOK && DNSSECRecordType(nsec->resrec.rrtype))
continue;
LogInfo("AddResourceRecords:NSEC Answering question with %s", CRDisplayString(m, nsec));
ttl = nsec->resrec.rroriginalttl - (now - nsec->TimeRcvd) / mDNSPlatformOneSecond;
ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.numAuthorities, &nsec->resrec, ttl, limit);
if (!ptr)
{
*prevptr = orig;
return mDNSNULL;
}
len += (ptr - orig);
orig = ptr;
}
if (soa)
{
LogInfo("AddResourceRecords: SOA Answering question with %s", CRDisplayString(m, soa));
ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.numAuthorities, &soa->resrec, soa->resrec.rroriginalttl, limit);
if (!ptr)
{
*prevptr = orig;
return mDNSNULL;
}
len += (ptr - orig);
orig = ptr;
}
if (cname)
{
AssignDomainName(&pc->q.qname, &cname->resrec.rdata->u.name);
pc->q.qnamehash = DomainNameHashValue(&pc->q.qname);
goto again;
}
if (!ptr)
{
LogInfo("AddResourceRecords: Did not find any valid ResourceRecords");
*error = mStatus_NoSuchRecord;
return mDNSNULL;
}
if (pc->rcvBufSize)
{
ptr = AddEDNS0Option(m, ptr, limit);
if (!ptr)
{
*prevptr = orig;
return mDNSNULL;
}
len += (ptr - orig);
orig = ptr;
}
LogInfo("AddResourceRecord: Added %d bytes to the packet", len);
return ptr;
}
mDNSlocal void ProxyClientCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
DNSProxyClient *pc = question->QuestionContext;
DNSProxyClient **ppc = &DNSProxyClients;
mDNSu8 *ptr;
mDNSu8 *prevptr;
mStatus error;
if (!AddRecord)
return;
LogInfo("ProxyClientCallback: ResourceRecord %s", RRDisplayString(m, answer));
// We asked for validation and not timed out yet, then wait for the DNSSEC result.
// We have to set the AD bit in the response if it is secure which can't be done
// till we get the DNSSEC result back (indicated by QC_dnssec).
if (question->ValidationRequired)
{
mDNSs32 now;
mDNS_Lock(m);
now = m->timenow;
mDNS_Unlock(m);
if (((now - question->StopTime) < 0) && AddRecord != QC_dnssec)
{
LogInfo("ProxyClientCallback: No DNSSEC answer yet for Question %##s (%s), AddRecord %d, answer %s", question->qname.c,
DNSTypeName(question->qtype), AddRecord, RRDisplayString(m, answer));
return;
}
}
if (answer->RecordType != kDNSRecordTypePacketNegative)
{
if (answer->rrtype != question->qtype)
{
// Wait till we get called for the real response
LogInfo("ProxyClientCallback: Received %s, not answering yet", RRDisplayString(m, answer));
return;
}
}
ptr = AddResourceRecords(m, pc, &prevptr, &error);
if (!ptr)
{
LogInfo("ProxyClientCallback: AddResourceRecords NULL for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype));
if (error == mStatus_NoError && prevptr)
{
// No space to add the record. Set the Truncate bit for UDP.
//
// TBD: For TCP, we need to send the rest of the data. But finding out what is left
// is harder. We should allocate enough buffer in the first place to send all
// of the data.
if (!pc->tcp)
{
m->omsg.h.flags.b[0] |= kDNSFlag0_TC;
ptr = prevptr;
}
else
{
LogInfo("ProxyClientCallback: ERROR!! Not enough space to return in TCP for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype));
ptr = prevptr;
}
}
else
{
mDNSOpaque16 flags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery, kDNSFlag1_RC_ServFail } };
// We could not find the record for some reason. Return a response, so that the client
// is not waiting forever.
LogInfo("ProxyClientCallback: No response");
if (!mDNSOpaque16IsZero(pc->q.responseFlags))
flags = pc->q.responseFlags;
InitializeDNSMessage(&m->omsg.h, pc->msgid, flags);
ptr = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &pc->qname, pc->q.qtype, pc->q.qclass);
if (!ptr)
{
LogInfo("ProxyClientCallback: putQuestion NULL for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype));
goto done;
}
}
}
if (question->ValidationRequired)
{
if (question->ValidationState == DNSSECValDone && question->ValidationStatus == DNSSEC_Secure)
{
LogInfo("ProxyClientCallback: Setting AD bit for Question %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
m->omsg.h.flags.b[1] |= kDNSFlag1_AD;
}
else
{
// If some external resolver sets the AD bit and we did not validate the response securely, don't set
// the AD bit. It is possible that we did not see all the records that the upstream resolver saw or
// a buggy implementation somewhere.
if (m->omsg.h.flags.b[1] & kDNSFlag1_AD)
{
LogInfo("ProxyClientCallback: AD bit set in the response for response that was not validated locally %##s (%s)",
question->qname.c, DNSTypeName(question->qtype));
m->omsg.h.flags.b[1] &= ~kDNSFlag1_AD;
}
}
}
if (!pc->tcp)
{
mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, (UDPSocket *)pc->socket, &pc->addr, pc->port, mDNSNULL, mDNSNULL, mDNSfalse);
}
else
{
mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &pc->addr, pc->port, (TCPSocket *)pc->socket, mDNSNULL, mDNSfalse);
}
done:
mDNS_StopQuery(m, question);
while (*ppc && *ppc != pc)
ppc=&(*ppc)->next;
if (!*ppc)
{
LogMsg("ProxyClientCallback: question %##s (%s) not found", question->qname.c, DNSTypeName(question->qtype));
return;
}
*ppc = pc->next;
mDNSPlatformDisposeProxyContext(pc->context);
FreeDNSProxyClient(pc);
}
mDNSlocal void SendError(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *dstaddr,
const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSBool tcp, void *context, mDNSu8 rcode)
{
int pktlen = (int)(end - (mDNSu8 *)pkt);
DNSMessage *msg = (DNSMessage *)pkt;
(void) InterfaceID;
// RFC 1035 requires that we copy the question back and RFC 2136 is okay with sending nothing
// in the body or send back whatever we get for updates. It is easy to return whatever we get
// in the question back to the responder. We return as much as we can fit in our standard
// output packet.
if (pktlen > AbsoluteMaxDNSMessageData)
pktlen = AbsoluteMaxDNSMessageData;
mDNSPlatformMemCopy(&m->omsg.h, &msg->h, sizeof(DNSMessageHeader));
m->omsg.h.flags.b[0] |= kDNSFlag0_QR_Response;
m->omsg.h.flags.b[1] = rcode;
mDNSPlatformMemCopy(m->omsg.data, (mDNSu8 *)&msg->h.numQuestions, pktlen);
if (!tcp)
{
mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, mDNSInterface_Any, socket, dstaddr, dstport, mDNSNULL, mDNSNULL,
mDNSfalse);
}
else
{
mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, mDNSInterface_Any, mDNSNULL, dstaddr, dstport, (TCPSocket *)socket,
mDNSNULL, mDNSfalse);
}
mDNSPlatformDisposeProxyContext(context);
}
mDNSlocal DNSQuestion *IsDuplicateClient(const mDNS *const m, const mDNSAddr *const addr, const mDNSIPPort port, const mDNSOpaque16 id,
const DNSQuestion *const question)
{
DNSProxyClient *pc;
(void) m; // unused
for (pc = DNSProxyClients; pc; pc = pc->next)
{
if (mDNSSameAddress(&pc->addr, addr) &&
mDNSSameIPPort(pc->port, port) &&
mDNSSameOpaque16(pc->msgid, id) &&
pc->q.qtype == question->qtype &&
pc->q.qclass == question->qclass &&
SameDomainName(&pc->qname, &question->qname))
{
LogInfo("IsDuplicateClient: Found a duplicate client in the list");
return(&pc->q);
}
}
return(mDNSNULL);
}
mDNSlocal mDNSBool CheckDNSProxyIpIntf(const mDNS *const m, mDNSInterfaceID InterfaceID)
{
int i;
mDNSu32 ip_ifindex = (mDNSu32)(unsigned long)InterfaceID;
LogInfo("CheckDNSProxyIpIntf: Stored Input Interface List: [%d] [%d] [%d] [%d] [%d]", m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2],
m->dp_ipintf[3], m->dp_ipintf[4]);
for (i = 0; i < MaxIp; i++)
{
if (ip_ifindex == m->dp_ipintf[i])
return mDNStrue;
}
return mDNSfalse;
}
mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSBool tcp, void *context)
{
DNSMessage *msg = (DNSMessage *)pkt;
mDNSu8 QR_OP;
const mDNSu8 *ptr;
DNSQuestion q, *qptr;
DNSProxyClient *pc;
const mDNSu8 *optRR;
int optLen = 0;
DNSProxyClient **ppc = &DNSProxyClients;
(void) dstaddr;
(void) dstport;
debugf("ProxyCallbackCommon: DNS Query coming from InterfaceID %p", InterfaceID);
// Ignore if the DNS Query is not from a Valid Input InterfaceID
if (!CheckDNSProxyIpIntf(m, InterfaceID))
return;
if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader))
{
debugf("ProxyCallbackCommon: DNS Message from %#a:%d to %#a:%d length %d too short", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt);
return;
}
QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
if (QR_OP != kDNSFlag0_QR_Query)
{
LogInfo("ProxyCallbackCommon: Not a query(%d) for pkt from %#a:%d", QR_OP, srcaddr, mDNSVal16(srcport));
SendError(m, socket, pkt, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_NotImpl);
return;
}
// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
ptr = (mDNSu8 *)&msg->h.numQuestions;
msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
if (msg->h.numQuestions != 1 || msg->h.numAnswers || msg->h.numAuthorities)
{
LogInfo("ProxyCallbackCommon: Malformed pkt from %#a:%d, Q:%d, An:%d, Au:%d", srcaddr, mDNSVal16(srcport),
msg->h.numQuestions, msg->h.numAnswers, msg->h.numAuthorities);
SendError(m, socket, pkt, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_FormErr);
return;
}
ptr = msg->data;
ptr = getQuestion(msg, ptr, end, InterfaceID, &q);
if (!ptr)
{
LogInfo("ProxyCallbackCommon: Question cannot be parsed for pkt from %#a:%d", srcaddr, mDNSVal16(srcport));
SendError(m, socket, pkt, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_FormErr);
return;
}
else
{
LogInfo("ProxyCallbackCommon: Question %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
}
ptr = LocateOptRR(msg, end, 0);
if (ptr)
{
optRR = ptr;
ptr = skipResourceRecord(msg, ptr, end);
// Be liberal and ignore the EDNS0 option if we can't parse it properly
if (!ptr)
{
LogInfo("ProxyCallbackCommon: EDNS0 cannot be parsed for pkt from %#a:%d, ignoring", srcaddr, mDNSVal16(srcport));
}
else
{
optLen = ptr - optRR;
LogInfo("ProxyCallbackCommon: EDNS0 opt length %d present in Question %##s (%s)", optLen, q.qname.c, DNSTypeName(q.qtype));
}
}
else
{
LogInfo("ProxyCallbackCommon: EDNS0 opt not present in Question %##s (%s), ptr %p", q.qname.c, DNSTypeName(q.qtype), ptr);
}
qptr = IsDuplicateClient(m, srcaddr, srcport, msg->h.id, &q);
if (qptr)
{
LogInfo("ProxyCallbackCommon: Found a duplicate for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
return;
}
pc = mDNSPlatformMemAllocate(sizeof(DNSProxyClient));
if (!pc)
{
LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
return;
}
mDNSPlatformMemZero(pc, sizeof(DNSProxyClient));
pc->addr = *srcaddr;
pc->port = srcport;
pc->msgid = msg->h.id;
pc->interfaceID = InterfaceID; // input interface
pc->socket = socket;
pc->tcp = tcp;
pc->requestFlags = msg->h.flags;
pc->context = context;
AssignDomainName(&pc->qname, &q.qname);
if (optRR)
{
if (!ParseEDNS0(pc, optRR, optLen, end))
{
LogInfo("ProxyCallbackCommon: Invalid EDNS0 option for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
}
else
{
pc->optRR = mDNSPlatformMemAllocate(optLen);
if (!pc->optRR)
{
LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
FreeDNSProxyClient(pc);
return;
}
mDNSPlatformMemCopy(pc->optRR, optRR, optLen);
pc->optLen = optLen;
}
}
debugf("ProxyCallbackCommon: DNS Query forwarding to interface index %d", m->dp_opintf);
mDNS_SetupQuestion(&pc->q, (mDNSInterfaceID)(unsigned long)m->dp_opintf, &q.qname, q.qtype, ProxyClientCallback, pc);
pc->q.TimeoutQuestion = 1;
// Even though we don't care about intermediate responses, set ReturnIntermed so that
// we get the negative responses
pc->q.ReturnIntermed = mDNStrue;
pc->q.ProxyQuestion = mDNStrue;
pc->q.ProxyDNSSECOK = pc->DNSSECOK;
pc->q.responseFlags = zeroID;
if (pc->DNSSECOK)
{
if (!(msg->h.flags.b[1] & kDNSFlag1_CD) && pc->q.qtype != kDNSType_RRSIG && pc->q.qtype != kDNSQType_ANY)
{
LogInfo("ProxyCallbackCommon: Setting Validation required bit for %#a:%d, validating %##s (%s)", srcaddr, mDNSVal16(srcport),
q.qname.c, DNSTypeName(q.qtype));
pc->q.ValidationRequired = DNSSEC_VALIDATION_SECURE;
}
else
{
LogInfo("ProxyCallbackCommon: CD bit not set OR not a valid type for %#a:%d, not validating %##s (%s)", srcaddr, mDNSVal16(srcport),
q.qname.c, DNSTypeName(q.qtype));
}
}
else
{
LogInfo("ProxyCallbackCommon: DNSSEC OK bit not set for %#a:%d, not validating %##s (%s)", srcaddr, mDNSVal16(srcport),
q.qname.c, DNSTypeName(q.qtype));
}
while (*ppc)
ppc = &((*ppc)->next);
*ppc = pc;
mDNS_StartQuery(m, &pc->q);
}
mDNSexport void ProxyUDPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
LogInfo("ProxyUDPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt);
ProxyCallbackCommon(m, socket, pkt, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, mDNSfalse, context);
}
mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
LogInfo("ProxyTCPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt);
// If the connection was closed from the other side, locate the client
// state and free it.
if ((end - (mDNSu8 *)pkt) == 0)
{
DNSProxyClient **ppc = &DNSProxyClients;
DNSProxyClient **prevpc;
prevpc = ppc;
while (*ppc && (*ppc)->socket != socket)
{
prevpc = ppc;
ppc=&(*ppc)->next;
}
if (!*ppc)
{
mDNSPlatformDisposeProxyContext(socket);
LogMsg("ProxyTCPCallback: socket cannot be found");
return;
}
*prevpc = (*ppc)->next;
LogInfo("ProxyTCPCallback: free");
mDNSPlatformDisposeProxyContext(socket);
FreeDNSProxyClient(*ppc);
return;
}
ProxyCallbackCommon(m, socket, pkt, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, mDNStrue, context);
}
mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
{
int i;
// Store DNSProxy Interface fields in mDNS struct
for (i = 0; i < MaxIp; i++)
m->dp_ipintf[i] = IpIfArr[i];
m->dp_opintf = OpIf;
LogInfo("DNSProxyInit Storing interface list: Input [%d, %d, %d, %d, %d] Output [%d]", m->dp_ipintf[0],
m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf);
}
mDNSexport void DNSProxyTerminate(mDNS *const m)
{
int i;
// Clear DNSProxy Interface fields from mDNS struct
for (i = 0; i < MaxIp; i++)
m->dp_ipintf[i] = 0;
m->dp_opintf = 0;
LogInfo("DNSProxyTerminate Cleared interface list: Input [%d, %d, %d, %d, %d] Output [%d]", m->dp_ipintf[0],
m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf);
}
#else // UNICAST_DISABLED
mDNSexport void ProxyUDPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
(void) m;
(void) socket;
(void) pkt;
(void) end;
(void) srcaddr;
(void) srcport;
(void) dstaddr;
(void) dstport;
(void) InterfaceID;
(void) context;
}
mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
(void) m;
(void) socket;
(void) pkt;
(void) end;
(void) srcaddr;
(void) srcport;
(void) dstaddr;
(void) dstport;
(void) InterfaceID;
(void) context;
}
mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
{
(void) m;
(void) IpIfArr;
(void) OpIf;
}
extern void DNSProxyTerminate(mDNS *const m)
{
(void) m;
}
#endif // UNICAST_DISABLED

View File

@ -0,0 +1,30 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DNS_PROXY_H
#define __DNS_PROXY_H
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
extern void ProxyUDPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context);
extern void ProxyTCPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context);
extern void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf);
extern void DNSProxyTerminate(mDNS *const m);
#endif // __DNS_PROXY_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DNSSEC_H
#define __DNSSEC_H
#include "CryptoAlg.h"
#include "mDNSDebug.h"
typedef enum
{
RRVS_rr, RRVS_rrsig, RRVS_key, RRVS_rrsig_key, RRVS_ds, RRVS_done,
} RRVerifierSet;
typedef struct RRVerifier_struct RRVerifier;
typedef struct DNSSECVerifier_struct DNSSECVerifier;
typedef struct AuthChain_struct AuthChain;
typedef struct InsecureContext_struct InsecureContext;
struct RRVerifier_struct
{
RRVerifier *next;
mDNSu16 rrtype;
mDNSu16 rrclass;
mDNSu32 rroriginalttl;
mDNSu16 rdlength;
mDNSu16 found;
mDNSu32 namehash;
mDNSu32 rdatahash;
domainname name;
mDNSu8 *rdata;
};
// Each AuthChain element has one rrset (with multiple resource records of same type), rrsig and key
// that validates the rrset.
struct AuthChain_struct
{
AuthChain *next; // Next element in the chain
RRVerifier *rrset; // RRSET that is authenticated
RRVerifier *rrsig; // Signature for that RRSET
RRVerifier *key; // Public key for that RRSET
};
#define ResetAuthChain(dv) { \
(dv)->ac = mDNSNULL; \
(dv)->actail = &((dv)->ac); \
}
typedef void DNSSECVerifierCallback (mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status);
//
// When we do a validation for a question, there might be additional validations that needs to be done e.g.,
// wildcard expanded answer. It is also possible that in the case of nsec we need to prove both that a wildcard
// does not apply and the closest encloser proves that name does not exist. We identify these with the following
// flags.
//
// Note: In the following, by "marking the validation", we mean that as part of validation we need to prove
// the ones that are marked with.
//
// A wildcard may be used to answer a question. In that case, we need to verify that the right wildcard was
// used in answering the question. This is done by marking the validation with WILDCARD_PROVES_ANSWER_EXPANDED.
//
// Sometimes we get a NXDOMAIN response. In this case, we may have a wildcard where we need to prove
// that the wildcard proves that the name does not exist. This is done by marking the validation with
// WILDCARD_PROVES_NONAME_EXISTS.
//
// In the case of NODATA error, sometimes the name may exist but the query type does not exist. This is done by
// marking the validation with NSEC_PROVES_NOTYPE_EXISTS.
//
// In both NXDOMAIN and NODATA proofs, we may have to prove that the NAME does not exist. This is done by marking
// the validation with NSEC_PROVES_NONAME_EXISTS.
//
#define WILDCARD_PROVES_ANSWER_EXPANDED 0x00000001
#define WILDCARD_PROVES_NONAME_EXISTS 0x00000002
#define NSEC_PROVES_NOTYPE_EXISTS 0x00000004
#define NSEC_PROVES_NONAME_EXISTS 0x00000008
#define NSEC3_OPT_OUT 0x00000010 // OptOut was set in NSEC3
struct DNSSECVerifier_struct
{
domainname origName; // Original question name that needs verification
mDNSu16 origType; // Original question type corresponding to origName
mDNSu16 currQtype; // Current question type that is being verified
mDNSInterfaceID InterfaceID; // InterfaceID of the question
DNSQuestion q;
mDNSu8 recursed; // Number of times recursed during validation
mDNSu8 ValidationRequired; // Copy of the question's ValidationRequired status
mDNSu8 InsecureProofDone;
mDNSu8 NumPackets; // Number of packets that we send on the wire for DNSSEC verification.
mDNSs32 StartTime; // Time the DNSSEC verification starts
mDNSu32 flags;
RRVerifierSet next;
domainname *wildcardName; // set if the answer is wildcard expanded
RRVerifier *pendingNSEC;
DNSSECVerifierCallback *DVCallback;
DNSSECVerifier *parent;
RRVerifier *rrset; // rrset for which we have to verify
RRVerifier *rrsig; // RRSIG for rrset
RRVerifier *key; // DNSKEY for rrset
RRVerifier *rrsigKey; // RRSIG for DNSKEY
RRVerifier *ds; // DS for DNSKEY set in parent zone
AuthChain *saveac;
AuthChain *ac;
AuthChain **actail;
AlgContext *ctx;
};
struct InsecureContext_struct
{
DNSSECVerifier *dv; // dv for which we are doing the insecure proof
mDNSu8 skip; // labels to skip for forming the name from origName
DNSSECStatus status; // status to deliver when done
mDNSu8 triggerLabelCount; // Label count of the name that triggered the insecure proof
DNSQuestion q;
};
#define LogDNSSEC LogOperation
#define DNS_SERIAL_GT(a, b) ((int)((a) - (b)) > 0)
#define DNS_SERIAL_LT(a, b) ((int)((a) - (b)) < 0)
extern void StartDNSSECVerification(mDNS *const m, void *context);
extern RRVerifier* AllocateRRVerifier(const ResourceRecord *const rr, mStatus *status);
extern mStatus AddRRSetToVerifier(DNSSECVerifier *dv, const ResourceRecord *const rr, RRVerifier *rv, RRVerifierSet set);
extern void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q);
extern void FreeDNSSECVerifier(mDNS *const m, DNSSECVerifier *dv);
extern DNSSECVerifier *AllocateDNSSECVerifier(mDNS *const m, const domainname *name, mDNSu16 rrtype, mDNSInterfaceID InterfaceID,
mDNSu8 ValidationRequired, DNSSECVerifierCallback dvcallback, mDNSQuestionCallback qcallback);
extern void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname,
mDNSu16 qtype, mDNSQuestionCallback *callback, void *context);
extern void ValidateRRSIG(DNSSECVerifier *dv, RRVerifierSet type, const ResourceRecord *const rr);
extern void AuthChainLink(DNSSECVerifier *dv, AuthChain *ae);
extern mStatus DNSNameToLowerCase(domainname *d, domainname *result);
extern int DNSMemCmp(const mDNSu8 *const m1, const mDNSu8 *const m2, int len);
extern int DNSSECCanonicalOrder(const domainname *const d1, const domainname *const d2, int *subdomain);
extern void ProveInsecure(mDNS *const m, DNSSECVerifier *dv, InsecureContext *ic, domainname *trigger);
extern void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value);
extern char *DNSSECStatusName(DNSSECStatus status);
// DNSSECProbe belongs in DNSSECSupport.h but then we don't want to expose yet another plaform specific dnssec file
// to other platforms where dnssec is not supported.
extern void DNSSECProbe(mDNS *const m);
#endif // __DNSSEC_H

File diff suppressed because it is too large Load Diff

View File

@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -37,13 +37,13 @@
#define MDNS_CHECK_PRINTF_STYLE_FUNCTIONS 0
typedef enum
{
MDNS_LOG_MSG,
MDNS_LOG_OPERATION,
MDNS_LOG_SPS,
MDNS_LOG_INFO,
MDNS_LOG_DEBUG,
} mDNSLogLevel_t;
{
MDNS_LOG_MSG,
MDNS_LOG_OPERATION,
MDNS_LOG_SPS,
MDNS_LOG_INFO,
MDNS_LOG_DEBUG,
} mDNSLogLevel_t;
// Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records
#define ANSWER_REMOTE_HOSTNAME_QUERIES 0
@ -64,62 +64,62 @@ typedef enum
#endif
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing.
#if (defined(__GNUC__))
#if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 2)))
#define MDNS_C99_VA_ARGS 1
#define MDNS_GNU_VA_ARGS 0
#else
#define MDNS_C99_VA_ARGS 0
#define MDNS_GNU_VA_ARGS 1
#endif
#define MDNS_HAS_VA_ARG_MACROS 1
#if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 2)))
#define MDNS_C99_VA_ARGS 1
#define MDNS_GNU_VA_ARGS 0
#else
#define MDNS_C99_VA_ARGS 0
#define MDNS_GNU_VA_ARGS 1
#endif
#define MDNS_HAS_VA_ARG_MACROS 1
#elif (_MSC_VER >= 1400) // Visual Studio 2005 and later
#define MDNS_C99_VA_ARGS 1
#define MDNS_GNU_VA_ARGS 0
#define MDNS_HAS_VA_ARG_MACROS 1
#define MDNS_C99_VA_ARGS 1
#define MDNS_GNU_VA_ARGS 0
#define MDNS_HAS_VA_ARG_MACROS 1
#elif (defined(__MWERKS__))
#define MDNS_C99_VA_ARGS 1
#define MDNS_GNU_VA_ARGS 0
#define MDNS_HAS_VA_ARG_MACROS 1
#define MDNS_C99_VA_ARGS 1
#define MDNS_GNU_VA_ARGS 0
#define MDNS_HAS_VA_ARG_MACROS 1
#else
#define MDNS_C99_VA_ARGS 0
#define MDNS_GNU_VA_ARGS 0
#define MDNS_HAS_VA_ARG_MACROS 0
#define MDNS_C99_VA_ARGS 0
#define MDNS_GNU_VA_ARGS 0
#define MDNS_HAS_VA_ARG_MACROS 0
#endif
#if (MDNS_HAS_VA_ARG_MACROS)
#if (MDNS_C99_VA_ARGS)
#define debug_noop( ... ) ((void)0)
#define LogMsg( ... ) LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__)
#define LogOperation( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__); } while (0)
#define LogSPS( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, __VA_ARGS__); } while (0)
#define LogInfo( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, __VA_ARGS__); } while (0)
#elif (MDNS_GNU_VA_ARGS)
#define debug_noop( ARGS... ) ((void)0)
#define LogMsg( ARGS... ) LogMsgWithLevel(MDNS_LOG_MSG, ARGS)
#define LogOperation( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, ARGS); } while (0)
#define LogSPS( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, ARGS); } while (0)
#define LogInfo( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, ARGS); } while (0)
#else
#error Unknown variadic macros
#endif
#if (MDNS_C99_VA_ARGS)
#define debug_noop(... ) ((void)0)
#define LogMsg(... ) LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__)
#define LogOperation(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__);} while (0)
#define LogSPS(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, __VA_ARGS__);} while (0)
#define LogInfo(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, __VA_ARGS__);} while (0)
#elif (MDNS_GNU_VA_ARGS)
#define debug_noop( ARGS... ) ((void)0)
#define LogMsg( ARGS... ) LogMsgWithLevel(MDNS_LOG_MSG, ARGS)
#define LogOperation( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, ARGS);} while (0)
#define LogSPS( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, ARGS);} while (0)
#define LogInfo( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, ARGS);} while (0)
#else
#error Unknown variadic macros
#endif
#else
// If your platform does not support variadic macros, you need to define the following variadic functions.
// See mDNSShared/mDNSDebug.c for sample implementation
#define debug_noop 1 ? (void)0 : (void)
#define LogMsg LogMsg_
#define LogOperation (mDNS_LoggingEnabled == 0) ? ((void)0) : LogOperation_
#define LogSPS (mDNS_LoggingEnabled == 0) ? ((void)0) : LogSPS_
#define LogInfo (mDNS_LoggingEnabled == 0) ? ((void)0) : LogInfo_
extern void LogMsg_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
extern void LogOperation_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
extern void LogSPS_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
extern void LogInfo_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
// If your platform does not support variadic macros, you need to define the following variadic functions.
// See mDNSShared/mDNSDebug.c for sample implementation
#define debug_noop 1 ? (void)0 : (void)
#define LogMsg LogMsg_
#define LogOperation (mDNS_LoggingEnabled == 0) ? ((void)0) : LogOperation_
#define LogSPS (mDNS_LoggingEnabled == 0) ? ((void)0) : LogSPS_
#define LogInfo (mDNS_LoggingEnabled == 0) ? ((void)0) : LogInfo_
extern void LogMsg_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
extern void LogOperation_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
extern void LogSPS_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
extern void LogInfo_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
#endif
#if MDNS_DEBUGMSGS
@ -136,9 +136,11 @@ extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1
#define verbosedebugf debug_noop
#endif
extern int mDNS_LoggingEnabled;
extern int mDNS_PacketLoggingEnabled;
extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog
extern int mDNS_LoggingEnabled;
extern int mDNS_PacketLoggingEnabled;
extern int mDNS_McastLoggingEnabled;
extern int mDNS_McastTracingEnabled;
extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog
extern const char ProgramName[];
extern void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
@ -158,7 +160,7 @@ extern void udns_validatelists(void *const v);
#endif
#ifdef __cplusplus
}
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __NSEC_H
#define __NSEC_H
#include "dnssec.h"
extern mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode);
extern void WildcardAnswerProof(mDNS *const m, DNSSECVerifier *dv);
extern void ValidateWithNSECS(mDNS *const m, DNSSECVerifier *dv, CacheRecord *rr);
extern mDNSBool NSECAnswersDS(mDNS *const m, ResourceRecord *rr, DNSQuestion *q);
extern int CountLabelsMatch(const domainname *const d1, const domainname *const d2);
extern void NameErrorNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status);
extern void VerifyNSEC(mDNS *const m, ResourceRecord *rr, RRVerifier *rv, DNSSECVerifier *pdv, CacheRecord *ncr,
DNSSECVerifierCallback callback);
extern CacheRecord *NSECRecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype);
extern void NoDataNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status);
#endif // __NSEC_H

View File

@ -0,0 +1,769 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// ***************************************************************************
// nsec3.c: This file contains support functions to validate NSEC3 records for
// NODATA and NXDOMAIN error.
// ***************************************************************************
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
#include "CryptoAlg.h"
#include "nsec3.h"
#include "nsec.h"
// Define DNSSEC_DISABLED to remove all the DNSSEC functionality
// and use the stub functions implemented later in this file.
#ifndef DNSSEC_DISABLED
typedef enum
{
NSEC3ClosestEncloser,
NSEC3Covers,
NSEC3CEProof
} NSEC3FindValues;
//#define NSEC3_DEBUG 1
#if NSEC3_DEBUG
mDNSlocal void PrintHash(mDNSu8 *digest, int digestlen, char *buffer, int buflen)
{
int length = 0;
for (int j = 0; j < digestlen; j++)
{
length += mDNS_snprintf(buffer+length, buflen-length-1, "%x", digest[j]);
}
}
#endif
mDNSlocal mDNSBool NSEC3OptOut(CacheRecord *cr)
{
const RDataBody2 *const rdb = (RDataBody2 *)cr->resrec.rdata->u.data;
rdataNSEC3 *nsec3 = (rdataNSEC3 *)rdb->data;
return (nsec3->flags & NSEC3_FLAGS_OPTOUT);
}
mDNSlocal int NSEC3SameName(const mDNSu8 *name, int namelen, const mDNSu8 *nsecName, int nsecLen)
{
int i;
// Note: With NSEC3, the lengths should always be same.
if (namelen != nsecLen)
{
LogMsg("NSEC3SameName: ERROR!! namelen %d, nsecLen %d", namelen, nsecLen);
return ((namelen < nsecLen) ? -1 : 1);
}
for (i = 0; i < namelen; i++)
{
mDNSu8 ac = *name++;
mDNSu8 bc = *nsecName++;
if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
if (ac != bc)
{
verbosedebugf("NSEC3SameName: returning ac %c, bc %c", ac, bc);
return ((ac < bc) ? -1 : 1);
}
}
return 0;
}
// Does the NSEC3 in "ncr" covers the "name" ?
// hashName is hash of the "name" and b32Name is the base32 encoded equivalent.
mDNSlocal mDNSBool NSEC3CoversName(mDNS *const m, CacheRecord *ncr, const mDNSu8 *hashName, int hashLen, const mDNSu8 *b32Name,
int b32len)
{
mDNSu8 *nxtName;
int nxtLength;
int ret, ret1, ret2;
const mDNSu8 b32nxtname[NSEC3_MAX_B32_LEN+1];
int b32nxtlen;
NSEC3Parse(&ncr->resrec, mDNSNULL, &nxtLength, &nxtName, mDNSNULL, mDNSNULL);
if (nxtLength != hashLen || ncr->resrec.name->c[0] != b32len)
return mDNSfalse;
// Compare the owner names and the "nxt" names.
//
// Owner name is base32 encoded and hence use the base32 encoded name b32name.
// nxt name is binary and hence use the binary value in hashName.
ret1 = NSEC3SameName(&ncr->resrec.name->c[1], ncr->resrec.name->c[0], b32Name, b32len);
ret2 = DNSMemCmp(nxtName, hashName, hashLen);
#if NSEC3_DEBUG
{
char nxtbuf1[50];
char nxtbuf2[50];
PrintHash(nxtName, nxtLength, nxtbuf1, sizeof(nxtbuf1));
PrintHash((mDNSu8 *)hashName, hashLen, nxtbuf2, sizeof(nxtbuf2));
LogMsg("NSEC3CoversName: Owner name %s, name %s", &ncr->resrec.name->c[1], b32Name);
LogMsg("NSEC3CoversName: Nxt hash name %s, name %s", nxtbuf1, nxtbuf2);
}
#endif
// "name" is greater than the owner name and smaller than nxtName. This also implies
// that nxtName > owner name implying that it is normal NSEC3.
if (ret1 < 0 && ret2 > 0)
{
LogDNSSEC("NSEC3CoversName: NSEC3 %s covers %s (Normal)", CRDisplayString(m, ncr), b32Name);
return mDNStrue;
}
// Need to compare the owner name and "nxt" to see if this is the last
// NSEC3 in the zone. Only the owner name is in base32 and hence we need to
// convert the nxtName to base32.
b32nxtlen = baseEncode((char *)b32nxtname, sizeof(b32nxtname), nxtName, nxtLength, ENC_BASE32);
if (!b32nxtlen)
{
LogDNSSEC("NSEC3CoversName: baseEncode of nxtName of %s failed", CRDisplayString(m, ncr));
return mDNSfalse;
}
if (b32len != b32nxtlen)
{
LogDNSSEC("NSEC3CoversName: baseEncode of nxtName for %s resulted in wrong length b32nxtlen %d, b32len %d",
CRDisplayString(m, ncr), b32len, b32nxtlen);
return mDNSfalse;
}
LogDNSSEC("NSEC3CoversName: Owner name %s, b32nxtname %s, ret1 %d, ret2 %d", &ncr->resrec.name->c[1], b32nxtname, ret1, ret2);
// If it is the last NSEC3 in the zone nxt < "name" and NSEC3SameName returns -1.
//
// - ret1 < 0 means "name > owner"
// - ret2 > 0 means "name < nxt"
//
// Note: We also handle the case of only NSEC3 in the zone where NSEC3SameName returns zero.
ret = NSEC3SameName(b32nxtname, b32nxtlen, &ncr->resrec.name->c[1], ncr->resrec.name->c[0]);
if (ret <= 0 &&
(ret1 < 0 || ret2 > 0))
{
LogDNSSEC("NSEC3CoversName: NSEC3 %s covers %s (Last), ret1 %d, ret2 %d", CRDisplayString(m, ncr), b32Name, ret1, ret2);
return mDNStrue;
}
return mDNSfalse;
}
// This function can be called with NSEC3ClosestEncloser, NSEC3Covers and NSEC3CEProof
//
// Passing in NSEC3ClosestEncloser means "find an exact match for the origName".
// Passing in NSEC3Covers means "find an NSEC3 that covers the origName".
//
// i.e., in both cases the nsec3 records are iterated to find the best match and returned.
// With NSEC3ClosestEncloser, as we are just looking for a name match, extra checks for
// the types being present or absent will not be checked.
//
// If NSEC3CEProof is passed, the name is tried as such first by iterating through all NSEC3s
// finding a ClosestEncloser or CloserEncloser and then one label skipped from the left and
// retried again till both the closest and closer encloser is found.
//
// ncr is the negative cache record that has the NSEC3 chain
// origName is the name for which we are trying to find the ClosestEncloser etc.
// closestEncloser and closerEncloser are the return values of the function
// ce is the closest encloser that will be returned if we find one
mDNSlocal mDNSBool NSEC3Find(mDNS *const m, NSEC3FindValues val, CacheRecord *ncr, domainname *origName, CacheRecord **closestEncloser,
CacheRecord **closerEncloser, const domainname **ce, mDNSu16 qtype)
{
int i;
int labelCount = CountLabels(origName);
CacheRecord *cr;
rdataNSEC3 *nsec3;
(void) qtype; // unused
// Pick the first NSEC for the iterations, salt etc.
for (cr = ncr->nsec; cr; cr = cr->next)
{
if (cr->resrec.rrtype == kDNSType_NSEC3)
{
const RDataBody2 *const rdb = (RDataBody2 *)cr->resrec.rdata->u.data;
nsec3 = (rdataNSEC3 *)rdb->data;
break;
}
}
if (!cr)
{
LogMsg("NSEC3Find: cr NULL");
return mDNSfalse;
}
// Note: The steps defined in this function are for "NSEC3CEProof". As part of NSEC3CEProof,
// we need to find both the closestEncloser and closerEncloser which can also be found
// by passing NSEC3ClosestEncloser and NSEC3Covers respectively.
//
// Section 8.3 of RFC 5155.
// 1. Set SNAME=QNAME. Clear the flag.
//
// closerEncloser is the "flag". "name" below is SNAME.
if (closestEncloser)
{
*ce = mDNSNULL;
*closestEncloser = mDNSNULL;
}
if (closerEncloser)
*closerEncloser = mDNSNULL;
// If we are looking for a closestEncloser or a covering NSEC3, we don't have
// to truncate the name. For the give name, try to find the closest or closer
// encloser.
if (val != NSEC3CEProof)
{
labelCount = 0;
}
for (i = 0; i < labelCount + 1; i++)
{
int hlen;
const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
const domainname *name;
const mDNSu8 b32Name[NSEC3_MAX_B32_LEN+1];
int b32len;
name = SkipLeadingLabels(origName, i);
if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
{
LogMsg("NSEC3Find: NSEC3HashName failed for ##s", name->c);
continue;
}
b32len = baseEncode((char *)b32Name, sizeof(b32Name), (mDNSu8 *)hashName, hlen, ENC_BASE32);
if (!b32len)
{
LogMsg("NSEC3Find: baseEncode of name %##s failed", name->c);
continue;
}
for (cr = ncr->nsec; cr; cr = cr->next)
{
const domainname *nsecZone;
int result, subdomain;
if (cr->resrec.rrtype != kDNSType_NSEC3)
continue;
nsecZone = SkipLeadingLabels(cr->resrec.name, 1);
if (!nsecZone)
{
LogMsg("NSEC3Find: SkipLeadingLabel failed for %s, current name %##s",
CRDisplayString(m, cr), name->c);
continue;
}
// NSEC3 owner names are formed by hashing the owner name and then appending
// the zone name to it. If we skip the first label, the rest should be
// the zone name. See whether it is the subdomain of the name we are looking
// for.
result = DNSSECCanonicalOrder(origName, nsecZone, &subdomain);
// The check can't be a strict subdomain check. When NSEC3ClosestEncloser is
// passed in, there can be an exact match. If it is a subdomain or an exact
// match, we should continue with the proof.
if (!(subdomain || !result))
{
LogMsg("NSEC3Find: NSEC3 %s not a subdomain of %##s, result %d", CRDisplayString(m, cr),
origName->c, result);
continue;
}
// 2.1) If there is no NSEC3 RR in the response that matches SNAME
// (i.e., an NSEC3 RR whose owner name is the same as the hash of
// SNAME, prepended as a single label to the zone name), clear
// the flag.
//
// Note: We don't try to determine the actual zone name. We know that
// the labels following the hash (nsecZone) is the ancestor and we don't
// know where the zone cut is. Hence, we verify just the hash to be
// the same.
if (val == NSEC3ClosestEncloser || val == NSEC3CEProof)
{
if (!NSEC3SameName(&cr->resrec.name->c[1], cr->resrec.name->c[0], (const mDNSu8 *)b32Name, b32len))
{
int bmaplen;
mDNSu8 *bmap;
// For NSEC3ClosestEncloser, we are finding an exact match and
// "type" specific checks should be done by the caller.
if (val != NSEC3ClosestEncloser)
{
// DNAME bit must not be set and NS bit may be set only if SOA bit is set
NSEC3Parse(&cr->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap);
if (BitmapTypeCheck(bmap, bmaplen, kDNSType_DNAME))
{
LogDNSSEC("NSEC3Find: DNAME bit set in %s, ignoring", CRDisplayString(m, cr));
return mDNSfalse;
}
// This is the closest encloser and should come from the right zone.
if (BitmapTypeCheck(bmap, bmaplen, kDNSType_NS) &&
!BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA))
{
LogDNSSEC("NSEC3Find: NS bit set without SOA bit in %s, ignoring", CRDisplayString(m, cr));
return mDNSfalse;
}
}
LogDNSSEC("NSEC3Find: ClosestEncloser %s found for name %##s", CRDisplayString(m, cr), name->c);
if (closestEncloser)
{
*ce = name;
*closestEncloser = cr;
}
if (val == NSEC3ClosestEncloser)
return mDNStrue;
else
break;
}
}
if ((val == NSEC3Covers || val == NSEC3CEProof) && !(*closerEncloser))
{
if (NSEC3CoversName(m, cr, hashName, hlen, b32Name, b32len))
{
// 2.2) If there is an NSEC3 RR in the response that covers SNAME, set the flag.
if (closerEncloser)
*closerEncloser = cr;
if (val == NSEC3Covers)
return mDNStrue;
else
break;
}
}
}
// 2.3) If there is a matching NSEC3 RR in the response and the flag
// was set, then the proof is complete, and SNAME is the closest
// encloser.
if (val == NSEC3CEProof)
{
if (*closestEncloser && *closerEncloser)
{
LogDNSSEC("NSEC3Find: Found closest and closer encloser");
return mDNStrue;
}
// 2.4) If there is a matching NSEC3 RR in the response, but the flag
// is not set, then the response is bogus.
//
// Note: We don't have to wait till we finish trying all the names. If the matchName
// happens, we found the closest encloser which means we should have found the closer
// encloser before.
if (*closestEncloser && !(*closerEncloser))
{
LogDNSSEC("NSEC3Find: Found closest, but not closer encloser");
return mDNSfalse;
}
}
// 3. Truncate SNAME by one label from the left, go to step 2.
}
LogDNSSEC("NSEC3Find: Cannot find name %##s (%s)", origName->c, DNSTypeName(qtype));
return mDNSfalse;
}
mDNSlocal mDNSBool NSEC3ClosestEncloserProof(mDNS *const m, CacheRecord *ncr, domainname *name, CacheRecord **closestEncloser, CacheRecord **closerEncloser,
const domainname **ce, mDNSu16 qtype)
{
if (!NSEC3Find(m, NSEC3CEProof, ncr, name, closestEncloser, closerEncloser, ce, qtype))
{
LogDNSSEC("NSEC3ClosestEncloserProof: ERROR!! Cannot do closest encloser proof");
return mDNSfalse;
}
// Note: It is possible that closestEncloser and closerEncloser are the same.
if (!closestEncloser || !closerEncloser || !ce)
{
LogMsg("NSEC3ClosestEncloserProof: ClosestEncloser %p or CloserEncloser %p ce %p, something is NULL", *closestEncloser,
*closerEncloser, *ce);
return mDNSfalse;
}
// If the name exists, we should not have gotten the name error
if (SameDomainName((*ce), name))
{
LogMsg("NSEC3ClosestEncloserProof: ClosestEncloser %s same as origName %##s", CRDisplayString(m, *closestEncloser),
(*ce)->c);
return mDNSfalse;
}
return mDNStrue;
}
mDNSlocal mDNSBool VerifyNSEC3(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr, CacheRecord *closestEncloser,
CacheRecord *closerEncloser, CacheRecord *wildcard, DNSSECVerifierCallback callback)
{
mStatus status;
RRVerifier *r;
// We have three NSEC3s. If any of two are same, we should just prove one of them.
// This is just not an optimization; DNSSECNegativeValidationCB does not handle
// identical NSEC3s very well.
if (closestEncloser == closerEncloser)
closestEncloser = mDNSNULL;
if (closerEncloser == wildcard)
closerEncloser = mDNSNULL;
if (closestEncloser == wildcard)
closestEncloser = mDNSNULL;
dv->pendingNSEC = mDNSNULL;
if (closestEncloser)
{
r = AllocateRRVerifier(&closestEncloser->resrec, &status);
if (!r)
return mDNSfalse;
r->next = dv->pendingNSEC;
dv->pendingNSEC = r;
}
if (closerEncloser)
{
r = AllocateRRVerifier(&closerEncloser->resrec, &status);
if (!r)
return mDNSfalse;
r->next = dv->pendingNSEC;
dv->pendingNSEC = r;
}
if (wildcard)
{
r = AllocateRRVerifier(&wildcard->resrec, &status);
if (!r)
return mDNSfalse;
r->next = dv->pendingNSEC;
dv->pendingNSEC = r;
}
if (!dv->pendingNSEC)
{
LogMsg("VerifyNSEC3: ERROR!! pending NSEC null");
return mDNSfalse;
}
r = dv->pendingNSEC;
dv->pendingNSEC = r->next;
r->next = mDNSNULL;
LogDNSSEC("VerifyNSEC3: Verifying %##s (%s)", r->name.c, DNSTypeName(r->rrtype));
if (!dv->pendingNSEC)
VerifyNSEC(m, mDNSNULL, r, dv, ncr, mDNSNULL);
else
VerifyNSEC(m, mDNSNULL, r, dv, ncr, callback);
return mDNStrue;
}
mDNSexport void NSEC3NameErrorProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr)
{
CacheRecord *closerEncloser;
CacheRecord *closestEncloser;
CacheRecord *wildcard;
const domainname *ce = mDNSNULL;
domainname wild;
if (!NSEC3ClosestEncloserProof(m, ncr, &dv->q.qname, &closestEncloser, &closerEncloser, &ce, dv->q.qtype))
{
goto error;
}
LogDNSSEC("NSEC3NameErrorProof: ClosestEncloser %s, ce %##s", CRDisplayString(m, closestEncloser), ce->c);
LogDNSSEC("NSEC3NameErrorProof: CloserEncloser %s", CRDisplayString(m, closerEncloser));
// *.closestEncloser should be covered by some nsec3 which would then prove
// that the wildcard does not exist
wild.c[0] = 1;
wild.c[1] = '*';
wild.c[2] = 0;
if (!AppendDomainName(&wild, ce))
{
LogMsg("NSEC3NameErrorProof: Can't append domainname to closest encloser name %##s", ce->c);
goto error;
}
if (!NSEC3Find(m, NSEC3Covers, ncr, &wild, mDNSNULL, &wildcard, mDNSNULL, dv->q.qtype))
{
LogMsg("NSEC3NameErrorProof: Cannot find encloser for wildcard");
goto error;
}
else
{
LogDNSSEC("NSEC3NameErrorProof: Wildcard %##s covered by %s", wild.c, CRDisplayString(m, wildcard));
if (wildcard == closestEncloser)
{
LogDNSSEC("NSEC3NameErrorProof: ClosestEncloser matching Wildcard %s", CRDisplayString(m, wildcard));
}
}
if (NSEC3OptOut(closerEncloser))
{
dv->flags |= NSEC3_OPT_OUT;
}
if (!VerifyNSEC3(m, dv, ncr, closestEncloser, closerEncloser, wildcard, NameErrorNSECCallback))
goto error;
else
return;
error:
dv->DVCallback(m, dv, DNSSEC_Bogus);
}
// Section 8.5, 8.6 of RFC 5155 first paragraph
mDNSlocal mDNSBool NSEC3NoDataError(mDNS *const m, CacheRecord *ncr, domainname *name, mDNSu16 qtype, CacheRecord **closestEncloser)
{
const domainname *ce = mDNSNULL;
*closestEncloser = mDNSNULL;
// Note: This also covers ENT in which case the bitmap is empty
if (NSEC3Find(m, NSEC3ClosestEncloser, ncr, name, closestEncloser, mDNSNULL, &ce, qtype))
{
int bmaplen;
mDNSu8 *bmap;
mDNSBool ns, soa;
NSEC3Parse(&(*closestEncloser)->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap);
if (BitmapTypeCheck(bmap, bmaplen, qtype) || BitmapTypeCheck(bmap, bmaplen, kDNSType_CNAME))
{
LogMsg("NSEC3NoDataError: qtype %s exists in %s", DNSTypeName(qtype), CRDisplayString(m, *closestEncloser));
return mDNSfalse;
}
ns = BitmapTypeCheck(bmap, bmaplen, kDNSType_NS);
soa = BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA);
if (qtype != kDNSType_DS)
{
// For non-DS type questions, we don't want to use the parent side records to
// answer it
if (ns && !soa)
{
LogDNSSEC("NSEC3NoDataError: Parent side NSEC %s, can't use for child qname %##s (%s)",
CRDisplayString(m, *closestEncloser), name->c, DNSTypeName(qtype));
return mDNSfalse;
}
}
else
{
if (soa)
{
LogDNSSEC("NSEC3NoDataError: Child side NSEC %s, can't use for parent qname %##s (%s)",
CRDisplayString(m, *closestEncloser), name->c, DNSTypeName(qtype));
return mDNSfalse;
}
}
LogDNSSEC("NSEC3NoDataError: Name -%##s- exists, but qtype %s does not exist in %s", name->c, DNSTypeName(qtype), CRDisplayString(m, *closestEncloser));
return mDNStrue;
}
return mDNSfalse;
}
mDNSexport void NSEC3NoDataProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr)
{
CacheRecord *closerEncloser = mDNSNULL;
CacheRecord *closestEncloser = mDNSNULL;
CacheRecord *wildcard = mDNSNULL;
const domainname *ce = mDNSNULL;
domainname wild;
// Section 8.5, 8.6 of RFC 5155
if (NSEC3NoDataError(m, ncr, &dv->q.qname, dv->q.qtype, &closestEncloser))
{
goto verify;
}
// Section 8.6, 8.7: if we can't find the NSEC3 RR, verify the closest encloser proof
// for QNAME and the "next closer" should have the opt out
if (!NSEC3ClosestEncloserProof(m, ncr, &dv->q.qname, &closestEncloser, &closerEncloser, &ce, dv->q.qtype))
{
goto error;
}
// Section 8.7: find a matching NSEC3 for *.closestEncloser
wild.c[0] = 1;
wild.c[1] = '*';
wild.c[2] = 0;
if (!AppendDomainName(&wild, ce))
{
LogMsg("NSEC3NameErrorProof: Can't append domainname to closest encloser name %##s", ce->c);
goto error;
}
if (!NSEC3Find(m, NSEC3ClosestEncloser, ncr, &wild, &wildcard, mDNSNULL, &ce, dv->q.qtype))
{
// Not a wild card case. Section 8.6 second para applies.
LogDNSSEC("NSEC3NoDataProof: Cannot find encloser for wildcard, perhaps not a wildcard case");
if (!NSEC3OptOut(closerEncloser))
{
LogDNSSEC("NSEC3DataProof: opt out not set for %##s (%s), bogus", dv->q.qname.c, DNSTypeName(dv->q.qtype));
goto error;
}
LogDNSSEC("NSEC3DataProof: opt out set, proof complete for %##s (%s)", dv->q.qname.c, DNSTypeName(dv->q.qtype));
dv->flags |= NSEC3_OPT_OUT;
}
else
{
int bmaplen;
mDNSu8 *bmap;
NSEC3Parse(&wildcard->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap);
if (BitmapTypeCheck(bmap, bmaplen, dv->q.qtype) || BitmapTypeCheck(bmap, bmaplen, kDNSType_CNAME))
{
LogDNSSEC("NSEC3NoDataProof: qtype %s exists in %s", DNSTypeName(dv->q.qtype), CRDisplayString(m, wildcard));
goto error;
}
if (dv->q.qtype == kDNSType_DS && BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA))
{
LogDNSSEC("NSEC3NoDataProof: Child side wildcard NSEC3 %s, can't use for parent qname %##s (%s)",
CRDisplayString(m, wildcard), dv->q.qname.c, DNSTypeName(dv->q.qtype));
goto error;
}
else if (dv->q.qtype != kDNSType_DS && !BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA) &&
BitmapTypeCheck(bmap, bmaplen, kDNSType_NS))
{
// Don't use the parent side record for this
LogDNSSEC("NSEC3NoDataProof: Parent side wildcard NSEC3 %s, can't use for child qname %##s (%s)",
CRDisplayString(m, wildcard), dv->q.qname.c, DNSTypeName(dv->q.qtype));
goto error;
}
LogDNSSEC("NSEC3NoDataProof: Wildcard %##s matched by %s", wild.c, CRDisplayString(m, wildcard));
}
verify:
if (!VerifyNSEC3(m, dv, ncr, closestEncloser, closerEncloser, wildcard, NoDataNSECCallback))
goto error;
else
return;
error:
dv->DVCallback(m, dv, DNSSEC_Bogus);
}
mDNSexport mDNSBool NSEC3WildcardAnswerProof(mDNS *const m, CacheRecord *ncr, DNSSECVerifier *dv)
{
int skip;
const domainname *nc;
CacheRecord *closerEncloser;
(void) m;
// Find the next closer name and prove that it is covered by the NSEC3
skip = CountLabels(&dv->origName) - CountLabels(dv->wildcardName) - 1;
if (skip)
nc = SkipLeadingLabels(&dv->origName, skip);
else
nc = &dv->origName;
LogDNSSEC("NSEC3WildcardAnswerProof: wildcard name %##s", nc->c);
if (!NSEC3Find(m, NSEC3Covers, ncr, (domainname *)nc, mDNSNULL, &closerEncloser, mDNSNULL, dv->q.qtype))
{
LogMsg("NSEC3WildcardAnswerProof: Cannot find closer encloser");
return mDNSfalse;
}
if (!closerEncloser)
{
LogMsg("NSEC3WildcardAnswerProof: closerEncloser NULL");
return mDNSfalse;
}
if (NSEC3OptOut(closerEncloser))
{
dv->flags |= NSEC3_OPT_OUT;
}
// NSEC3 Verification is done by the caller
return mDNStrue;
}
mDNSexport CacheRecord *NSEC3RecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype)
{
CacheGroup *cg;
CacheRecord *cr;
CacheRecord *ncr;
mDNSu32 slot, namehash;
slot = HashSlot(name);
namehash = DomainNameHashValue(name);
cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, name);
if (!cg)
{
LogDNSSEC("NSEC3RecordForName: cg NULL for %##s", name);
return mDNSNULL;
}
for (ncr = cg->members; ncr; ncr = ncr->next)
{
if (ncr->resrec.RecordType != kDNSRecordTypePacketNegative ||
ncr->resrec.rrtype != qtype)
{
continue;
}
for (cr = ncr->nsec; cr; cr = cr->next)
{
int hlen, b32len;
const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
const mDNSu8 b32Name[NSEC3_MAX_B32_LEN+1];
const RDataBody2 *const rdb = (RDataBody2 *)cr->resrec.rdata->u.data;
rdataNSEC3 *nsec3;
if (cr->resrec.rrtype != kDNSType_NSEC3)
continue;
nsec3 = (rdataNSEC3 *)rdb->data;
if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
{
LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for ##s", name->c);
return mDNSNULL;
}
b32len = baseEncode((char *)b32Name, sizeof(b32Name), (mDNSu8 *)hashName, hlen, ENC_BASE32);
if (!b32len)
{
LogMsg("NSEC3RecordIsDelegation: baseEncode of name %##s failed", name->c);
return mDNSNULL;
}
// Section 2.3 of RFC 4035 states that:
//
// Each owner name in the zone that has authoritative data or a delegation point NS RRset MUST
// have an NSEC resource record.
//
// This applies to NSEC3 record. So, if we have an NSEC3 record matching the question name with the
// NS bit set, then this is a delegation.
//
if (!NSEC3SameName(&cr->resrec.name->c[1], cr->resrec.name->c[0], (const mDNSu8 *)b32Name, b32len))
{
int bmaplen;
mDNSu8 *bmap;
LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s matches name %##s, b32name %s", CRDisplayString(m, cr), name->c, b32Name);
NSEC3Parse(&cr->resrec, mDNSNULL, mDNSNULL, mDNSNULL, &bmaplen, &bmap);
// See the Insecure Delegation Proof section in dnssec-bis: DS bit and SOA bit
// should be absent
if (BitmapTypeCheck(bmap, bmaplen, kDNSType_SOA) ||
BitmapTypeCheck(bmap, bmaplen, kDNSType_DS))
{
LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s has DS or SOA bit set, ignoring", CRDisplayString(m, cr));
return mDNSNULL;
}
if (BitmapTypeCheck(bmap, bmaplen, kDNSType_NS))
return cr;
else
return mDNSNULL;
}
// If opt-out is not set, then it does not cover any delegations
if (!(nsec3->flags & NSEC3_FLAGS_OPTOUT))
continue;
// Opt-out allows insecure delegations to exist without the NSEC3 RR at the
// hashed owner name (see RFC 5155 section 6.0).
if (NSEC3CoversName(m, cr, hashName, hlen, b32Name, b32len))
{
LogDNSSEC("NSEC3RecordIsDelegation: CacheRecord %s covers name %##s with optout", CRDisplayString(m, cr), name->c);
return cr;
}
}
}
return mDNSNULL;
}
#else // !DNSSEC_DISABLED
#endif // !DNSSEC_DISABLED

View File

@ -0,0 +1,28 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __NSEC3_H
#define __NSEC3_H
#include "dnssec.h"
extern mDNSBool NSEC3WildcardAnswerProof(mDNS *const m, CacheRecord *ncr, DNSSECVerifier *dv);
extern void NSEC3NameErrorProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr);
extern void NSEC3NoDataProof(mDNS *const m, DNSSECVerifier *dv, CacheRecord *ncr);
extern CacheRecord *NSEC3RecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype);
#endif // __NSEC3_H

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
* Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -21,19 +21,24 @@
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
#ifdef __cplusplus
extern "C" {
#ifdef __cplusplus
extern "C" {
#endif
#define RESTART_GOODBYE_DELAY (6 * mDNSPlatformOneSecond) // delay after restarting LLQ before nuking previous known answers (avoids flutter if we restart before we have networking up)
#define INIT_UCAST_POLL_INTERVAL (3 * mDNSPlatformOneSecond) // this interval is used after send failures on network transitions
// which typically heal quickly, so we start agressively and exponentially back off
// which typically heal quickly, so we start agressively and exponentially back off
#define MAX_UCAST_POLL_INTERVAL (60 * 60 * mDNSPlatformOneSecond)
//#define MAX_UCAST_POLL_INTERVAL (1 * 60 * mDNSPlatformOneSecond)
#define LLQ_POLL_INTERVAL (15 * 60 * mDNSPlatformOneSecond) // Polling interval for zones w/ an advertised LLQ port (ie not static zones) if LLQ fails due to NAT, etc.
#define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond) // require server responses within one minute of request
#define MAX_UCAST_UNANSWERED_QUERIES 2 // the number of unanswered queries from any one uDNS server before trying another server
#define DNSSERVER_PENALTY_TIME (60 * mDNSPlatformOneSecond) // number of seconds for which new questions don't pick this server
#define MAX_DNSSEC_UNANSWERED_QUERIES 1 // number of unanswered queries from any one uDNS server before turning off DNSSEC Validation
#define MAX_UCAST_UNANSWERED_QUERIES 2 // number of unanswered queries from any one uDNS server before trying another server
#define DNSSERVER_PENALTY_TIME (60 * mDNSPlatformOneSecond) // number of seconds for which new questions don't pick this server
// On some interfaces, we want to delay the first retransmission to a minimum of 2 seconds
// rather than the default (1 second).
#define MIN_UCAST_RETRANS_TIMEOUT (2 * mDNSPlatformOneSecond)
#define DEFAULT_UPDATE_LEASE 7200
@ -41,22 +46,35 @@
#define QuestionIntervalStep2 (QuestionIntervalStep*QuestionIntervalStep)
#define QuestionIntervalStep3 (QuestionIntervalStep*QuestionIntervalStep*QuestionIntervalStep)
#define InitialQuestionInterval ((mDNSPlatformOneSecond + QuestionIntervalStep-1) / QuestionIntervalStep)
#define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
// just move to MaxQuestionInterval once over this threshold
#define QuestionIntervalThreshold (QuestionIntervalStep3 * mDNSPlatformOneSecond)
// For Unicast record registrations, we initialize the interval to 1 second. When we send any query for
// the record registration e.g., GetZoneData, we always back off by QuestionIntervalStep
// so that the first retry does not happen until 3 seconds which should be enough for TCP/TLS to be done.
#define INIT_RECORD_REG_INTERVAL (1 * mDNSPlatformOneSecond)
#define MAX_RECORD_REG_INTERVAL (15 * 60 * mDNSPlatformOneSecond)
#define MERGE_DELAY_TIME (1 * mDNSPlatformOneSecond)
#define MAX_RECORD_REG_INTERVAL (15 * 60 * mDNSPlatformOneSecond)
#define MERGE_DELAY_TIME (1 * mDNSPlatformOneSecond)
// If we are refreshing, we do it at least 5 times with a min update frequency of
// If we are refreshing, we do it at least 5 times with a min update frequency of
// 5 minutes
#define MAX_UPDATE_REFRESH_COUNT 5
#define MIN_UPDATE_REFRESH_TIME (5 * 60 * mDNSPlatformOneSecond)
#define MAX_UPDATE_REFRESH_COUNT 5
#define MIN_UPDATE_REFRESH_TIME (5 * 60 * mDNSPlatformOneSecond)
// For questions that use kDNSServiceFlagsTimeout and we don't have a matching resolver e.g., no dns servers,
// then use the default value of 30 seconds
#define DEFAULT_UDNS_TIMEOUT 30 // in seconds
#define DEFAULT_UDNS_TIMEOUT 30 // in seconds
// For questions that are validating responses (q->ValidatingResponse == 1), use 10 seconds
// which accomodates two DNS servers and two queries per DNS server.
#define DEFAULT_UDNSSEC_TIMEOUT 10 // in seconds
// If we are sending queries with EDNS0/DO option and we have no indications that the server
// is DNSSEC aware and we have already reached MAX_DNSSEC_RETRANSMISSIONS, we disable
// validation (for optional case only) for any questions that uses this server
#define MAX_DNSSEC_RETRANSMISSIONS 3
// Entry points into unicast-specific routines
@ -75,7 +93,6 @@ extern void SleepRecordRegistrations(mDNS *m);
extern mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr);
extern void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q);
extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name);
extern mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr);
extern mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt);
extern mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question);
@ -89,7 +106,7 @@ extern void uDNS_CheckCurrentQuestion(mDNS *const m);
// integer fields of msg header must be in HOST byte order before calling this routine
extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
extern void uDNS_Tasks(mDNS *const m);
extern void UpdateAllSRVRecords(mDNS *m);
@ -97,23 +114,25 @@ extern void CheckNATMappings(mDNS *m);
extern mStatus uDNS_SetupDNSConfig(mDNS *const m);
// uDNS_SetupSearchDomains by default adds search domains. It also can be called with one or
// more values for "action" which does the following:
//
// -UDNS_START_WAB_QUERY - start Wide Area Bonjour (domain enumeration) queries
// uDNS_SetupWABQueries reads search domains from the platform layer and starts the Wide Area Bonjour
// (WAB) domain enumeration queries if necessary.
#define UDNS_START_WAB_QUERY 0x00000001
#define UDNS_WAB_BROWSE_QUERY 0x00000001 // Browse queries (b, db)
#define UDNS_WAB_LBROWSE_QUERY 0x00000002 // Browse queries (lb)
#define UDNS_WAB_REG_QUERY 0x00000004 // Registration queries (r and dr)
extern mStatus uDNS_SetupSearchDomains(mDNS *const m, int action);
extern void uDNS_SetupWABQueries(mDNS *const m);
extern void uDNS_StartWABQueries(mDNS *const m, int queryType);
extern void uDNS_StopWABQueries(mDNS *const m, int queryType);
extern domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal);
typedef enum
{
uDNS_LLQ_Not = 0, // Normal uDNS answer: Flush any stale records from cache, and respect record TTL
uDNS_LLQ_Ignore, // LLQ initial challenge packet: ignore -- has no useful records for us
uDNS_LLQ_Entire, // LLQ initial set of answers: Flush any stale records from cache, but assume TTL is 2 x LLQ refresh interval
uDNS_LLQ_Events // LLQ event packet: don't flush cache; assume TTL is 2 x LLQ refresh interval
} uDNS_LLQType;
{
uDNS_LLQ_Not = 0, // Normal uDNS answer: Flush any stale records from cache, and respect record TTL
uDNS_LLQ_Ignore, // LLQ initial challenge packet: ignore -- has no useful records for us
uDNS_LLQ_Entire, // LLQ initial set of answers: Flush any stale records from cache, but assume TTL is 2 x LLQ refresh interval
uDNS_LLQ_Events // LLQ event packet: don't flush cache; assume TTL is 2 x LLQ refresh interval
} uDNS_LLQType;
extern uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, DNSQuestion **matchQuestion);
extern DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name);
@ -121,12 +140,12 @@ extern DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const
extern void DisposeTCPConn(struct tcpInfo_t *tcp);
// NAT traversal
extern void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len); // Called for each received NAT-PMP packet
extern void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr);
extern void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease);
extern void uDNS_ReceiveNATPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len); // Called for each received PCP or NAT-PMP packet
extern void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr);
extern void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease, NATTProtocol protocol);
#ifdef __cplusplus
}
#ifdef __cplusplus
}
#endif
#endif // __UDNS_H_

View File

@ -5,18 +5,18 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
File: daemon.c
File: daemon.c
Contains: main & associated Application layer for mDNSResponder on Linux.
Contains: main & associated Application layer for mDNSResponder on Linux.
*/
@ -45,15 +45,10 @@ extern int daemon(int, int);
#include "mDNSEmbeddedAPI.h"
#include "mDNSPosix.h"
#include "mDNSUNP.h" // For daemon()
#include "mDNSUNP.h" // For daemon()
#include "uds_daemon.h"
#include "DNSCommon.h"
#include "PlatformCommon.h"
#ifndef MDNSD_USER
#define MDNSD_USER "nobody"
#endif
#define CONFIG_FILE "/etc/mdnsd.conf"
static domainname DynDNSZone; // Default wide-area zone for service registration
static domainname DynDNSHostname;
@ -63,264 +58,201 @@ static CacheEntity gRRCache[RR_CACHE_SIZE];
static mDNS_PlatformSupport PlatformStorage;
mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
{
(void)m; // Unused
if (result == mStatus_NoError)
{
// On successful registration of dot-local mDNS host name, daemon may want to check if
// any name conflict and automatic renaming took place, and if so, record the newly negotiated
// name in persistent storage for next time. It should also inform the user of the name change.
// On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store,
// and notify the user with a CFUserNotification.
}
else if (result == mStatus_ConfigChanged)
{
udsserver_handle_configchange(m);
}
else if (result == mStatus_GrowCache)
{
// Allocate another chunk of cache storage
CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE);
if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
}
}
{
(void)m; // Unused
if (result == mStatus_NoError)
{
// On successful registration of dot-local mDNS host name, daemon may want to check if
// any name conflict and automatic renaming took place, and if so, record the newly negotiated
// name in persistent storage for next time. It should also inform the user of the name change.
// On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store,
// and notify the user with a CFUserNotification.
}
else if (result == mStatus_ConfigChanged)
{
udsserver_handle_configchange(m);
}
else if (result == mStatus_GrowCache)
{
// Allocate another chunk of cache storage
CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE);
if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
}
}
// %%% Reconfigure() probably belongs in the platform support layer (mDNSPosix.c), not the daemon cde
// -- all client layers running on top of mDNSPosix.c need to handle network configuration changes,
// not only the Unix Domain Socket Daemon
static void Reconfigure(mDNS *m)
{
mDNSAddr DynDNSIP;
const mDNSAddr dummy = { mDNSAddrType_IPv4, { { { 1, 1, 1, 1 } } } };;
mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
mDNS_Lock(m);
if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
mDNS_Unlock(m);
ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy);
if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
mDNS_ConfigChanged(m);
}
{
mDNSAddr DynDNSIP;
const mDNSAddr dummy = { mDNSAddrType_IPv4, { { { 1, 1, 1, 1 } } } };;
mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy);
if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
mDNS_ConfigChanged(m);
}
// Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
{
if (argc > 1)
{
if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
else printf("Usage: %s [-debug]\n", argv[0]);
}
{
if (argc > 1)
{
if (0 == strcmp(argv[1], "-debug")) mDNS_DebugMode = mDNStrue;
else printf("Usage: %s [-debug]\n", argv[0]);
}
if (!mDNS_DebugMode)
{
int result = daemon(0, 0);
if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); }
if (!mDNS_DebugMode)
{
int result = daemon(0, 0);
if (result != 0) { LogMsg("Could not run as daemon - exiting"); exit(result); }
#if __APPLE__
LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting");
exit(-1);
LogMsg("The POSIX mdnsd should only be used on OS X for testing - exiting");
exit(-1);
#endif
}
}
}
}
mDNSlocal void DumpStateLog(mDNS *const m)
// Dump a little log of what we've been up to.
{
DNSServer *s;
PosixNetworkInterface *i;
LogMsg("---- BEGIN STATE LOG ----");
udsserver_info(m);
LogMsgNoIdent("----- Network Interfaces -------");
for (i = (PosixNetworkInterface*)(m->HostInterfaces);
i; i = (PosixNetworkInterface *)(i->coreIntf.next)) {
LogMsg("%p %p %d %s%s%s%s%s %-8s %#a", i,
(void *)(i->coreIntf.InterfaceID), i->index,
i->coreIntf.InterfaceActive ? "-" : "D",
i->coreIntf.IPv4Available ? "4" : "-",
i->coreIntf.IPv6Available ? "6" : "-",
i->coreIntf.Advertise ? "A" : "-",
i->coreIntf.McastTxRx ? "M" : "-",
i->intfName, &(i->coreIntf.ip));
}
LogMsgNoIdent("--------- DNS Servers ----------");
if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
else
{
for (s = m->DNSServers; s; s = s->next)
{
LogMsgNoIdent("DNS Server %##s %#a:%d %s",
s->domain.c, &s->addr, mDNSVal16(s->port),
s->teststate == DNSServer_Untested ? "(Untested)" :
s->teststate == DNSServer_Passed ? "" :
s->teststate == DNSServer_Failed ? "(Failed)" :
s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)");
}
}
LogMsg("---- END STATE LOG ----");
}
{
LogMsg("---- BEGIN STATE LOG ----");
udsserver_info(m);
LogMsg("---- END STATE LOG ----");
}
mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
{
sigset_t signals;
mDNSBool gotData = mDNSfalse;
{
sigset_t signals;
mDNSBool gotData = mDNSfalse;
mDNSPosixListenForSignalInEventLoop(SIGINT);
mDNSPosixListenForSignalInEventLoop(SIGTERM);
mDNSPosixListenForSignalInEventLoop(SIGUSR1);
#ifdef HAVE_SIGINFO
mDNSPosixListenForSignalInEventLoop(SIGUSR2);
mDNSPosixListenForSignalInEventLoop(SIGINFO);
#endif
mDNSPosixListenForSignalInEventLoop(SIGPIPE);
mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
mDNSPosixListenForSignalInEventLoop(SIGINT);
mDNSPosixListenForSignalInEventLoop(SIGTERM);
mDNSPosixListenForSignalInEventLoop(SIGUSR1);
mDNSPosixListenForSignalInEventLoop(SIGPIPE);
mDNSPosixListenForSignalInEventLoop(SIGHUP) ;
for (; ;)
{
// Work out how long we expect to sleep before the next scheduled task
struct timeval timeout;
mDNSs32 ticks;
for (; ;)
{
// Work out how long we expect to sleep before the next scheduled task
struct timeval timeout;
mDNSs32 ticks;
// Only idle if we didn't find any data the last time around
if (!gotData)
{
mDNSs32 nextTimerEvent = mDNS_Execute(m);
nextTimerEvent = udsserver_idle(nextTimerEvent);
ticks = nextTimerEvent - mDNS_TimeNow(m);
if (ticks < 1) ticks = 1;
}
else // otherwise call EventLoop again with 0 timemout
ticks = 0;
// Only idle if we didn't find any data the last time around
if (!gotData)
{
mDNSs32 nextTimerEvent = mDNS_Execute(m);
nextTimerEvent = udsserver_idle(nextTimerEvent);
ticks = nextTimerEvent - mDNS_TimeNow(m);
if (ticks < 1) ticks = 1;
}
else // otherwise call EventLoop again with 0 timemout
ticks = 0;
timeout.tv_sec = ticks / mDNSPlatformOneSecond;
timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
timeout.tv_sec = ticks / mDNSPlatformOneSecond;
timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * 1000000 / mDNSPlatformOneSecond;
(void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
(void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
if (sigismember(&signals, SIGHUP )) Reconfigure(m);
#ifdef HAVE_SIGINFO
/* use OSX-compatible signals since we can, and gain enhanced debugging */
if (sigismember(&signals, SIGINFO)) DumpStateLog(m);
if (sigismember(&signals, SIGUSR1))
{
mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1;
LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
}
if (sigismember(&signals, SIGUSR2))
{
mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1;
LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
}
#else
if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
#endif
// SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
}
return EINTR;
}
if (sigismember(&signals, SIGHUP )) Reconfigure(m);
if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
// SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
}
return EINTR;
}
int main(int argc, char **argv)
{
mStatus err;
{
mStatus err;
ParseCmdLinArgs(argc, argv);
ParseCmdLinArgs(argc, argv);
LogMsg("%s starting", mDNSResponderVersionString);
LogMsg("%s starting", mDNSResponderVersionString);
err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
if (mStatus_NoError == err)
err = udsserver_init(mDNSNULL, 0);
Reconfigure(&mDNSStorage);
if (mStatus_NoError == err)
err = udsserver_init(mDNSNULL, 0);
// Now that we're finished with anything privileged, switch over to running as "nobody"
if (mStatus_NoError == err)
{
const struct passwd *pw = getpwnam(MDNSD_USER);
if (pw != NULL)
{
setgid(pw->pw_gid);
setuid(pw->pw_uid);
}
else
#ifdef MDNSD_NOROOT
{
LogMsg("WARNING: mdnsd exiting because user \""MDNSD_USER"\" does not exist");
err = mStatus_Invalid;
}
#else
LogMsg("WARNING: mdnsd continuing as root because user \""MDNSD_USER"\" does not exist");
#endif
}
Reconfigure(&mDNSStorage);
if (mStatus_NoError == err)
err = MainLoop(&mDNSStorage);
LogMsg("%s stopping", mDNSResponderVersionString);
// Now that we're finished with anything privileged, switch over to running as "nobody"
if (mStatus_NoError == err)
{
const struct passwd *pw = getpwnam("nobody");
if (pw != NULL)
setuid(pw->pw_uid);
else
LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
}
mDNS_Close(&mDNSStorage);
if (mStatus_NoError == err)
err = MainLoop(&mDNSStorage);
LogMsg("%s stopping", mDNSResponderVersionString);
mDNS_Close(&mDNSStorage);
if (udsserver_exit() < 0)
LogMsg("ExitCallback: udsserver_exit failed");
if (udsserver_exit() < 0)
LogMsg("ExitCallback: udsserver_exit failed");
#if MDNS_DEBUGMSGS > 0
printf("mDNSResponder exiting normally with %ld\n", err);
printf("mDNSResponder exiting normally with %ld\n", err);
#endif
return err;
}
return err;
}
// uds_daemon support ////////////////////////////////////////////////////////////
mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context, void **platform_data)
/* Support routine for uds_daemon.c */
{
// Depends on the fact that udsEventCallback == mDNSPosixEventCallback
(void) platform_data;
return mDNSPosixAddFDToEventLoop(fd, callback, context);
}
{
// Depends on the fact that udsEventCallback == mDNSPosixEventCallback
(void) platform_data;
return mDNSPosixAddFDToEventLoop(fd, callback, context);
}
int udsSupportReadFD(dnssd_sock_t fd, char *buf, int len, int flags, void *platform_data)
{
(void) platform_data;
return recv(fd, buf, len, flags);
}
{
(void) platform_data;
return recv(fd, buf, len, flags);
}
mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data) // Note: This also CLOSES the file descriptor
{
mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
(void) platform_data;
close(fd);
return err;
}
mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data) // Note: This also CLOSES the file descriptor
{
mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
(void) platform_data;
close(fd);
return err;
}
mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
{
(void)m;
(void)delay;
// No-op, for now
}
{
(void)m;
(void)delay;
// No-op, for now
}
#if _BUILDING_XCODE_PROJECT_
// If the process crashes, then this string will be magically included in the automatically-generated crash log
const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
asm(".desc ___crashreporter_info__, 0x10");
asm (".desc ___crashreporter_info__, 0x10");
#endif
// For convenience when using the "strings" command, this is the last thing in the file
#if mDNSResponderVersion > 1
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion);
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
#elif MDNS_VERSIONSTR_NODTS
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
#else
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ")";
#endif

File diff suppressed because it is too large Load Diff

View File

@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -22,7 +22,7 @@
#include <sys/time.h>
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
// PosixNetworkInterface is a record extension of the core NetworkInterfaceInfo
@ -34,32 +34,33 @@
typedef struct PosixNetworkInterface PosixNetworkInterface;
struct PosixNetworkInterface
{
NetworkInterfaceInfo coreIntf;
const char * intfName;
PosixNetworkInterface * aliasIntf;
int index;
int multicastSocket4;
{
NetworkInterfaceInfo coreIntf; // MUST be the first element in this structure
mDNSs32 LastSeen;
const char * intfName;
PosixNetworkInterface * aliasIntf;
int index;
int multicastSocket4;
#if HAVE_IPV6
int multicastSocket6;
int multicastSocket6;
#endif
};
};
// This is a global because debugf_() needs to be able to check its value
extern int gMDNSPlatformPosixVerboseLevel;
struct mDNS_PlatformSupport_struct
{
int unicastSocket4;
{
int unicastSocket4;
#if HAVE_IPV6
int unicastSocket6;
int unicastSocket6;
#endif
};
};
#define uDNS_SERVERS_FILE "/etc/resolv.conf"
extern int ParseDNSServers(mDNS *m, const char *filePath);
extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
// See comment in implementation.
// See comment in implementation.
// Call mDNSPosixGetFDSet before calling select(), to update the parameters
// as may be necessary to meet the needs of the mDNSCore code.
@ -70,7 +71,7 @@ extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout);
extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds);
typedef void (*mDNSPosixEventCallback)(int fd, short filter, void *context);
typedef void (*mDNSPosixEventCallback)(int fd, short filter, void *context);
extern mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context);
extern mStatus mDNSPosixRemoveFDFromEventLoop( int fd);
@ -79,7 +80,7 @@ extern mStatus mDNSPosixIgnoreSignalInEventLoop( int signum);
extern mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, sigset_t *pSignalsReceived, mDNSBool *pDataDispatched);
#ifdef __cplusplus
}
}
#endif
#endif

View File

@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -31,33 +31,31 @@
macro, usually defined in <sys/param.h> or someplace like that, to make sure the
CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
should be set to the name of the header to include to get the ALIGN(P) macro.
*/
*/
#ifdef NEED_ALIGN_MACRO
#include NEED_ALIGN_MACRO
#endif
/* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
other platforms don't even have that include file. So,
if we haven't yet got a definition, let's try to find
/* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
other platforms don't even have that include file. So,
if we haven't yet got a definition, let's try to find
<sys/sockio.h>.
*/
*/
#ifndef SIOCGIFCONF
#include <sys/sockio.h>
#endif
/* sockaddr_dl is only referenced if we're using IP_RECVIF,
/* sockaddr_dl is only referenced if we're using IP_RECVIF,
so only include the header in that case.
*/
*/
#ifdef IP_RECVIF
#include <net/if_dl.h>
#endif
#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX && !defined(sun)
#if defined(__FreeBSD__) || defined(__DragonFly__)
#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
#include <net/if_var.h>
#endif
#include <netinet/in_var.h>
// Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
#endif
@ -68,151 +66,177 @@
/* Converts a prefix length to IPv6 network mask */
void plen_to_mask(int plen, char *addr) {
int i;
int colons=7; /* Number of colons in IPv6 address */
int bits_in_block=16; /* Bits per IPv6 block */
for(i=0;i<=colons;i++) {
int block, ones=0xffff, ones_in_block;
if (plen>bits_in_block) ones_in_block=bits_in_block;
else ones_in_block=plen;
block = ones & (ones << (bits_in_block-ones_in_block));
i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
plen -= ones_in_block;
}
}
int i;
int colons=7; /* Number of colons in IPv6 address */
int bits_in_block=16; /* Bits per IPv6 block */
for(i=0; i<=colons; i++) {
int block, ones=0xffff, ones_in_block;
if (plen>bits_in_block) ones_in_block=bits_in_block;
else ones_in_block=plen;
block = ones & (ones << (bits_in_block-ones_in_block));
i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
plen -= ones_in_block;
}
}
/* Gets IPv6 interface information from the /proc filesystem in linux*/
struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
{
struct ifi_info *ifi, *ifihead, **ifipnext;
FILE *fp;
char addr[8][5];
int flags, myflags, index, plen, scope;
char ifname[9], lastname[IFNAMSIZ];
char addr6[32+7+1]; /* don't forget the seven ':' */
struct addrinfo hints, *res0;
struct sockaddr_in6 *sin6;
struct in6_addr *addrptr;
int err;
{
struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
FILE *fp;
char addr[8][5];
int flags, myflags, index, plen, scope;
char ifname[9], lastname[IFNAMSIZ];
char addr6[32+7+1]; /* don't forget the seven ':' */
struct addrinfo hints, *res0;
struct sockaddr_in6 *sin6;
struct in6_addr *addrptr;
int err;
int sockfd = -1;
struct ifreq ifr;
res0=NULL;
ifihead = NULL;
ifipnext = &ifihead;
lastname[0] = 0;
res0=NULL;
ifihead = NULL;
ifipnext = &ifihead;
lastname[0] = 0;
if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
while (fscanf(fp,
"%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
addr[0],addr[1],addr[2],addr[3],
addr[4],addr[5],addr[6],addr[7],
&index, &plen, &scope, &flags, ifname) != EOF) {
if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sockfd < 0) {
goto gotError;
}
while (fscanf(fp,
"%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
addr[0],addr[1],addr[2],addr[3],
addr[4],addr[5],addr[6],addr[7],
&index, &plen, &scope, &flags, ifname) != EOF) {
char ipv6addr[INET6_ADDRSTRLEN];
myflags = 0;
if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
if (doaliases == 0)
continue; /* already processed this interface */
myflags = IFI_ALIAS;
}
memcpy(lastname, ifname, IFNAMSIZ);
ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
if (ifi == NULL) {
goto gotError;
}
myflags = 0;
if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
if (doaliases == 0)
continue; /* already processed this interface */
myflags = IFI_ALIAS;
}
memcpy(lastname, ifname, IFNAMSIZ);
ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
if (ifi == NULL) {
goto gotError;
}
ifipold = *ifipnext; /* need this later */
ifiptr = ifipnext;
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
addr[0],addr[1],addr[2],addr[3],
addr[4],addr[5],addr[6],addr[7]);
sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
addr[0],addr[1],addr[2],addr[3],
addr[4],addr[5],addr[6],addr[7]);
/* Add address of the interface */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_flags = AI_NUMERICHOST;
err = getaddrinfo(addr6, NULL, &hints, &res0);
if (err) {
goto gotError;
}
ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
if (ifi->ifi_addr == NULL) {
goto gotError;
}
memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
/* Add address of the interface */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_flags = AI_NUMERICHOST;
err = getaddrinfo(addr6, NULL, &hints, &res0);
if (err) {
goto gotError;
}
ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
if (ifi->ifi_addr == NULL) {
goto gotError;
}
memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
/* Add netmask of the interface */
plen_to_mask(plen, ipv6addr);
ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
if (ifi->ifi_addr == NULL) {
goto gotError;
}
sin6=calloc(1, sizeof(struct sockaddr_in6));
addrptr=calloc(1, sizeof(struct in6_addr));
inet_pton(family, ipv6addr, addrptr);
sin6->sin6_family=family;
sin6->sin6_addr=*addrptr;
sin6->sin6_scope_id=scope;
memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
free(sin6);
/* Add netmask of the interface */
char ipv6addr[INET6_ADDRSTRLEN];
plen_to_mask(plen, ipv6addr);
ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
if (ifi->ifi_addr == NULL) {
goto gotError;
}
sin6=calloc(1, sizeof(struct sockaddr_in6));
addrptr=calloc(1, sizeof(struct in6_addr));
inet_pton(family, ipv6addr, addrptr);
sin6->sin6_family=family;
sin6->sin6_addr=*addrptr;
sin6->sin6_scope_id=scope;
memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
free(sin6);
/* Add interface name */
memcpy(ifi->ifi_name, ifname, IFI_NAME);
/* Add interface name */
memcpy(ifi->ifi_name, ifname, IFI_NAME);
/* Add interface index */
ifi->ifi_index = index;
/* Add interface index */
ifi->ifi_index = index;
/* If interface is in /proc then it is up*/
ifi->ifi_flags = IFF_UP;
/* Add interface flags*/
memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
if (errno == EADDRNOTAVAIL) {
/*
* If the main interface is configured with no IP address but
* an alias interface exists with an IP address, you get
* EADDRNOTAVAIL for the main interface
*/
free(ifi->ifi_addr);
free(ifi);
ifipnext = ifiptr;
*ifipnext = ifipold;
continue;
} else {
goto gotError;
}
}
ifi->ifi_flags = ifr.ifr_flags;
freeaddrinfo(res0);
res0=NULL;
}
}
goto done;
freeaddrinfo(res0);
res0=NULL;
}
}
goto done;
gotError:
if (ifihead != NULL) {
free_ifi_info(ifihead);
ifihead = NULL;
}
if (res0 != NULL) {
freeaddrinfo(res0);
res0=NULL;
}
done:
return(ifihead); /* pointer to first structure in linked list */
}
gotError:
if (ifihead != NULL) {
free_ifi_info(ifihead);
ifihead = NULL;
}
if (res0 != NULL) {
freeaddrinfo(res0);
res0=NULL;
}
done:
if (sockfd != -1) {
assert(close(sockfd) == 0);
}
return(ifihead); /* pointer to first structure in linked list */
}
#endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
struct ifi_info *get_ifi_info(int family, int doaliases)
{
int junk;
struct ifi_info *ifi, *ifihead, **ifipnext;
int sockfd, sockf6, len, lastlen, flags, myflags;
int junk;
struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
int sockfd, sockf6, len, lastlen, flags, myflags;
#ifdef NOT_HAVE_IF_NAMETOINDEX
int index = 200;
int index = 200;
#endif
char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
struct ifconf ifc;
struct ifconf ifc;
struct ifreq *ifr, ifrcopy;
struct sockaddr_in *sinptr;
#if defined(AF_INET6) && HAVE_IPV6
struct sockaddr_in6 *sinptr6;
#endif
#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
#endif
sockfd = -1;
sockfd = -1;
sockf6 = -1;
buf = NULL;
ifihead = NULL;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
goto gotError;
@ -255,7 +279,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
// fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
if (ifr->ifr_addr.sa_family != family)
continue; /* ignore if not desired address family */
@ -273,35 +297,19 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
goto gotError;
}
flags = ifrcopy.ifr_flags;
if ((flags & IFF_UP) == 0)
continue; /* ignore if interface not up */
/* Skip addresses we can't use */
#ifdef SIOCGIFAFLAG_IN6
if (ifr->ifr_addr.sa_family == AF_INET6) {
struct in6_ifreq ifr6;
if (sockf6 == -1)
sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
memset(&ifr6, 0, sizeof(ifr6));
memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name));
memcpy(&ifr6.ifr_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_addr));
if (ioctl(sockf6, SIOCGIFAFLAG_IN6, &ifr6) < 0)
goto gotError;
if (ifr6.ifr_ifru.ifru_flags6 &
(IN6_IFF_NOTREADY | IN6_IFF_DETACHED))
continue;
}
#endif
ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
if (ifi == NULL) {
goto gotError;
}
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
ifipold = *ifipnext; /* need this later */
ifiptr = ifipnext;
*ifipnext = ifi; /* prev points to this new one */
ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
ifi->ifi_flags = flags; /* IFF_xxx values */
ifi->ifi_myflags = myflags; /* IFI_xxx values */
@ -310,11 +318,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
#else
ifrcopy = *ifr;
#ifdef SIOCGIFINDEX
if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
ifi->ifi_index = ifrcopy.ifr_index;
else
#endif
ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
#endif
memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
ifi->ifi_name[IFI_NAME-1] = '\0';
@ -331,16 +339,32 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
#ifdef SIOCGIFNETMASK
if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
if (ifi->ifi_netmask == NULL) goto gotError;
sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
if (errno == EADDRNOTAVAIL) {
/*
* If the main interface is configured with no IP address but
* an alias interface exists with an IP address, you get
* EADDRNOTAVAIL for the main interface
*/
free(ifi->ifi_addr);
free(ifi);
ifipnext = ifiptr;
*ifipnext = ifipold;
continue;
} else {
goto gotError;
}
}
ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
if (ifi->ifi_netmask == NULL) goto gotError;
sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
#ifndef NOT_HAVE_SA_LEN
sinptr->sin_len = sizeof(struct sockaddr_in);
sinptr->sin_len = sizeof(struct sockaddr_in);
#endif
sinptr->sin_family = AF_INET;
memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
sinptr->sin_family = AF_INET;
memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
#endif
#ifdef SIOCGIFBRDADDR
@ -349,11 +373,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
goto gotError;
}
sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
#ifndef NOT_HAVE_SA_LEN
sinptr->sin_len = sizeof( struct sockaddr_in );
sinptr->sin_len = sizeof( struct sockaddr_in );
#endif
sinptr->sin_family = AF_INET;
sinptr->sin_family = AF_INET;
ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
if (ifi->ifi_brdaddr == NULL) {
goto gotError;
@ -370,9 +394,9 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
#ifndef NOT_HAVE_SA_LEN
sinptr->sin_len = sizeof( struct sockaddr_in );
sinptr->sin_len = sizeof( struct sockaddr_in );
#endif
sinptr->sin_family = AF_INET;
sinptr->sin_family = AF_INET;
ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
if (ifi->ifi_dstaddr == NULL) {
goto gotError;
@ -391,27 +415,42 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
if (ifi->ifi_addr == NULL) {
goto gotError;
}
/* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
/* We need to strip that out */
if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
#ifdef SIOCGIFNETMASK_IN6
{
struct in6_ifreq ifr6;
if (sockf6 == -1)
sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
memset(&ifr6, 0, sizeof(ifr6));
memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
if (ifi->ifi_netmask == NULL) goto gotError;
sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
}
{
struct in6_ifreq ifr6;
if (sockf6 == -1)
sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
memset(&ifr6, 0, sizeof(ifr6));
memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
if (errno == EADDRNOTAVAIL) {
/*
* If the main interface is configured with no IP address but
* an alias interface exists with an IP address, you get
* EADDRNOTAVAIL for the main interface
*/
free(ifi->ifi_addr);
free(ifi);
ifipnext = ifiptr;
*ifipnext = ifipold;
continue;
} else {
goto gotError;
}
}
ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
if (ifi->ifi_netmask == NULL) goto gotError;
sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
}
#endif
}
break;
@ -422,7 +461,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
}
}
goto done;
gotError:
if (ifihead != NULL) {
free_ifi_info(ifihead);
@ -466,22 +505,22 @@ free_ifi_info(struct ifi_info *ifihead)
}
/* end free_ifi_info */
ssize_t
ssize_t
recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
{
struct msghdr msg;
struct iovec iov[1];
ssize_t n;
struct msghdr msg;
struct iovec iov[1];
ssize_t n;
#ifdef CMSG_FIRSTHDR
struct cmsghdr *cmptr;
union {
struct cmsghdr cm;
char control[1024];
struct cmsghdr cm;
char control[1024];
} control_un;
*ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
*ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
@ -503,12 +542,12 @@ recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
*salenptr = msg.msg_namelen; /* pass back results */
if (pktp) {
/* 0.0.0.0, i/f = -1 */
/* We set the interface to -1 so that the caller can
tell whether we returned a meaningful value or
just some default. Previously this code just
set the value to 0, but I'm concerned that 0
/* We set the interface to -1 so that the caller can
tell whether we returned a meaningful value or
just some default. Previously this code just
set the value to 0, but I'm concerned that 0
might be a valid interface value.
*/
*/
memset(pktp, 0, sizeof(struct my_in_pktinfo));
pktp->ipi_ifindex = -1;
}
@ -516,7 +555,7 @@ recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
/* include recvfrom_flags2 */
#ifndef CMSG_FIRSTHDR
#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
*flagsp = 0; /* pass back results */
return(n);
#else
@ -531,18 +570,18 @@ recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
#ifdef IP_PKTINFO
#if in_pktinfo_definition_is_missing
struct in_pktinfo
{
int ipi_ifindex;
struct in_addr ipi_spec_dst;
struct in_addr ipi_addr;
};
struct in_pktinfo
{
int ipi_ifindex;
struct in_addr ipi_spec_dst;
struct in_addr ipi_addr;
};
#endif
if (cmptr->cmsg_level == IPPROTO_IP &&
if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_PKTINFO) {
struct in_pktinfo *tmp;
struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
sin->sin_family = AF_INET;
sin->sin_addr = tmp->ipi_addr;
@ -556,7 +595,7 @@ struct in_pktinfo
if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_RECVDSTADDR) {
struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
sin->sin_family = AF_INET;
sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
sin->sin_port = 0;
@ -574,10 +613,10 @@ struct in_pktinfo
#endif
pktp->ipi_ifindex = sdl->sdl_index;
#ifdef HAVE_BROKEN_RECVIF_NAME
if (sdl->sdl_index == 0) {
pktp->ipi_ifindex = *(uint_t*)sdl;
}
#endif
if (sdl->sdl_index == 0) {
pktp->ipi_ifindex = *(uint_t*)sdl;
}
#endif
assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
// null terminated because of memset above
continue;
@ -587,22 +626,22 @@ struct in_pktinfo
#ifdef IP_RECVTTL
if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_RECVTTL) {
*ttl = *(u_char*)CMSG_DATA(cmptr);
*ttl = *(u_char*)CMSG_DATA(cmptr);
continue;
}
else if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
*ttl = *(int*)CMSG_DATA(cmptr);
cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
*ttl = *(int*)CMSG_DATA(cmptr);
continue;
}
#endif
#if defined(IPV6_PKTINFO) && HAVE_IPV6
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_PKTINFO) {
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_2292_PKTINFO) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
sin6->sin6_family = AF_INET6;
#ifndef NOT_HAVE_SA_LEN
sin6->sin6_len = sizeof(*sin6);
@ -611,15 +650,15 @@ struct in_pktinfo
sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
sin6->sin6_port = 0;
pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
continue;
}
#endif
#if defined(IPV6_HOPLIMIT) && HAVE_IPV6
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_HOPLIMIT) {
*ttl = *(int*)CMSG_DATA(cmptr);
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
*ttl = *(int*)CMSG_DATA(cmptr);
continue;
}
#endif
@ -640,41 +679,41 @@ struct in_pktinfo
#include <sys/signal.h>
int daemon(int nochdir, int noclose)
{
switch (fork())
{
switch (fork())
{
case -1: return (-1); // Fork failed
case 0: break; // Child -- continue
default: _exit(0); // Parent -- exit
}
if (setsid() == -1) return(-1);
signal(SIGHUP, SIG_IGN);
switch (fork()) // Fork again, primarily for reasons of Unix trivia
{
case -1: return (-1); // Fork failed
case 0: break; // Child -- continue
default: _exit(0); // Parent -- exit
}
if (!nochdir) (void)chdir("/");
umask(0);
if (!noclose)
{
int fd = open("/dev/null", O_RDWR, 0);
if (fd != -1)
{
// Avoid unnecessarily duplicating a file descriptor to itself
if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
(void)close (fd);
}
}
return (0);
case -1: return (-1); // Fork failed
case 0: break; // Child -- continue
default: _exit(0); // Parent -- exit
}
if (setsid() == -1) return(-1);
signal(SIGHUP, SIG_IGN);
switch (fork()) // Fork again, primarily for reasons of Unix trivia
{
case -1: return (-1); // Fork failed
case 0: break; // Child -- continue
default: _exit(0); // Parent -- exit
}
if (!nochdir) (void)chdir("/");
umask(0);
if (!noclose)
{
int fd = open("/dev/null", O_RDWR, 0);
if (fd != -1)
{
// Avoid unnecessarily duplicating a file descriptor to itself
if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
(void)close (fd);
}
}
return (0);
}
#endif /* NOT_HAVE_DAEMON */

View File

@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -25,14 +25,23 @@
#ifdef HAVE_LINUX
#include <linux/socket.h>
#define IPV6_2292_PKTINFO IPV6_2292PKTINFO
#define IPV6_2292_HOPLIMIT IPV6_2292HOPLIMIT
#else
// The following are the supported non-linux posix OSes -
// netbsd, freebsd and openbsd.
#if HAVE_IPV6
#define IPV6_2292_PKTINFO 19
#define IPV6_2292_HOPLIMIT 20
#endif
#endif
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
#ifdef NOT_HAVE_SOCKLEN_T
typedef unsigned int socklen_t;
typedef unsigned int socklen_t;
#endif
#if !defined(_SS_MAXSIZE)
@ -40,7 +49,7 @@
#define sockaddr_storage sockaddr_in6
#else
#define sockaddr_storage sockaddr
#endif // HAVE_IPV6
#endif // HAVE_IPV6
#endif // !defined(_SS_MAXSIZE)
#ifndef NOT_HAVE_SA_LEN
@ -60,8 +69,8 @@
struct my_in_pktinfo {
struct sockaddr_storage ipi_addr;
int ipi_ifindex; /* received interface index */
char ipi_ifname[IFI_NAME]; /* received interface name */
int ipi_ifindex; /* received interface index */
char ipi_ifname[IFI_NAME]; /* received interface name */
};
/* From the text (Stevens, section 20.2): */
@ -71,33 +80,33 @@ struct my_in_pktinfo {
/* 2. the destination addres of the received datagram (from the IP_RECVDSTADDR socket option, and */
/* 3. the index of the interface on which the datagram was received (the IP_RECVIF socket option).' */
extern ssize_t recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl);
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl);
struct ifi_info {
char ifi_name[IFI_NAME]; /* interface name, null terminated */
u_char ifi_haddr[IFI_HADDR]; /* hardware address */
u_short ifi_hlen; /* #bytes in hardware address: 0, 6, 8 */
short ifi_flags; /* IFF_xxx constants from <net/if.h> */
short ifi_myflags; /* our own IFI_xxx flags */
int ifi_index; /* interface index */
struct sockaddr *ifi_addr; /* primary address */
struct sockaddr *ifi_netmask;
struct sockaddr *ifi_brdaddr;/* broadcast address */
struct sockaddr *ifi_dstaddr;/* destination address */
struct ifi_info *ifi_next; /* next of these structures */
char ifi_name[IFI_NAME]; /* interface name, null terminated */
u_char ifi_haddr[IFI_HADDR]; /* hardware address */
u_short ifi_hlen; /* #bytes in hardware address: 0, 6, 8 */
short ifi_flags; /* IFF_xxx constants from <net/if.h> */
short ifi_myflags; /* our own IFI_xxx flags */
int ifi_index; /* interface index */
struct sockaddr *ifi_addr; /* primary address */
struct sockaddr *ifi_netmask;
struct sockaddr *ifi_brdaddr; /* broadcast address */
struct sockaddr *ifi_dstaddr; /* destination address */
struct ifi_info *ifi_next; /* next of these structures */
};
#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
#define PROC_IFINET6_PATH "/proc/net/if_inet6"
extern struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases);
#endif
#if defined(AF_INET6) && HAVE_IPV6
#define INET6_ADDRSTRLEN 46 /*Maximum length of IPv6 address */
#endif
#define IFI_ALIAS 1 /* ifi_addr is an alias */
/* From the text (Stevens, section 16.6): */
@ -115,7 +124,7 @@ extern int daemon(int nochdir, int noclose);
#endif
#ifdef __cplusplus
}
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -5,315 +5,315 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
File: GenLinkedList.c
File: GenLinkedList.c
Contains: implementation of generic linked lists.
Contains: implementation of generic linked lists.
Version: 1.0
Tabs: 4 spaces
Version: 1.0
Tabs: 4 spaces
*/
#include "GenLinkedList.h"
// Return the link pointer contained within element e at offset o.
#define GETLINK( e, o) ( *(void**)((char*) (e) + (o)) )
#define GETLINK( e, o) ( *(void**)((char*) (e) + (o)) )
// Assign the link pointer l to element e at offset o.
#define ASSIGNLINK( e, l, o) ( *((void**)((char*) (e) + (o))) = (l))
#define ASSIGNLINK( e, l, o) ( *((void**)((char*) (e) + (o))) = (l))
// GenLinkedList /////////////////////////////////////////////////////////////
void InitLinkedList( GenLinkedList *pList, size_t linkOffset)
void InitLinkedList( GenLinkedList *pList, size_t linkOffset)
/* Initialize the block of memory pointed to by pList as a linked list. */
{
pList->Head = NULL;
pList->Tail = NULL;
pList->LinkOffset = linkOffset;
pList->Head = NULL;
pList->Tail = NULL;
pList->LinkOffset = linkOffset;
}
void AddToTail( GenLinkedList *pList, void *elem)
void AddToTail( GenLinkedList *pList, void *elem)
/* Add a linked list element to the tail of the list. */
{
if ( pList->Tail) {
ASSIGNLINK( pList->Tail, elem, pList->LinkOffset);
} else
pList->Head = elem;
ASSIGNLINK( elem, NULL, pList->LinkOffset);
if ( pList->Tail) {
ASSIGNLINK( pList->Tail, elem, pList->LinkOffset);
} else
pList->Head = elem;
ASSIGNLINK( elem, NULL, pList->LinkOffset);
pList->Tail = elem;
pList->Tail = elem;
}
void AddToHead( GenLinkedList *pList, void *elem)
void AddToHead( GenLinkedList *pList, void *elem)
/* Add a linked list element to the head of the list. */
{
ASSIGNLINK( elem, pList->Head, pList->LinkOffset);
if ( pList->Tail == NULL)
pList->Tail = elem;
ASSIGNLINK( elem, pList->Head, pList->LinkOffset);
if ( pList->Tail == NULL)
pList->Tail = elem;
pList->Head = elem;
pList->Head = elem;
}
int RemoveFromList( GenLinkedList *pList, void *elem)
int RemoveFromList( GenLinkedList *pList, void *elem)
/* Remove a linked list element from the list. Return 0 if it was not found. */
/* If the element is removed, its link will be set to NULL. */
{
void *iElem, *lastElem;
void *iElem, *lastElem;
for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) {
if ( iElem == elem) {
if ( lastElem) { // somewhere past the head
ASSIGNLINK( lastElem, GETLINK( elem, pList->LinkOffset), pList->LinkOffset);
} else { // at the head
pList->Head = GETLINK( elem, pList->LinkOffset);
}
if ( pList->Tail == elem)
pList->Tail = lastElem ? lastElem : NULL;
ASSIGNLINK( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug.
return 1;
}
lastElem = iElem;
}
return 0;
for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) {
if ( iElem == elem) {
if ( lastElem) { // somewhere past the head
ASSIGNLINK( lastElem, GETLINK( elem, pList->LinkOffset), pList->LinkOffset);
} else { // at the head
pList->Head = GETLINK( elem, pList->LinkOffset);
}
if ( pList->Tail == elem)
pList->Tail = lastElem ? lastElem : NULL;
ASSIGNLINK( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug.
return 1;
}
lastElem = iElem;
}
return 0;
}
int ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem)
int ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem)
/* Replace an element in the list with a new element, in the same position. */
{
void *iElem, *lastElem;
void *iElem, *lastElem;
if ( elemInList == NULL || newElem == NULL)
return 0;
if ( elemInList == NULL || newElem == NULL)
return 0;
for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset))
{
if ( iElem == elemInList)
{
ASSIGNLINK( newElem, GETLINK( elemInList, pList->LinkOffset), pList->LinkOffset);
if ( lastElem) // somewhere past the head
{
ASSIGNLINK( lastElem, newElem, pList->LinkOffset);
}
else // at the head
{
pList->Head = newElem;
}
if ( pList->Tail == elemInList)
pList->Tail = newElem;
return 1;
}
lastElem = iElem;
}
for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset))
{
if ( iElem == elemInList)
{
ASSIGNLINK( newElem, GETLINK( elemInList, pList->LinkOffset), pList->LinkOffset);
if ( lastElem) // somewhere past the head
{
ASSIGNLINK( lastElem, newElem, pList->LinkOffset);
}
else // at the head
{
pList->Head = newElem;
}
if ( pList->Tail == elemInList)
pList->Tail = newElem;
return 1;
}
lastElem = iElem;
}
return 0;
return 0;
}
// GenDoubleLinkedList /////////////////////////////////////////////////////////
void InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset,
size_t backLinkOffset)
void InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset,
size_t backLinkOffset)
/* Initialize the block of memory pointed to by pList as a double linked list. */
{
pList->Head = NULL;
pList->Tail = NULL;
pList->FwdLinkOffset = fwdLinkOffset;
pList->BackLinkOffset = backLinkOffset;
pList->Head = NULL;
pList->Tail = NULL;
pList->FwdLinkOffset = fwdLinkOffset;
pList->BackLinkOffset = backLinkOffset;
}
void DLLAddToHead( GenDoubleLinkedList *pList, void *elem)
void DLLAddToHead( GenDoubleLinkedList *pList, void *elem)
/* Add a linked list element to the head of the list. */
{
void *pNext;
void *pNext;
pNext = pList->Head;
pNext = pList->Head;
// fix up the forward links
ASSIGNLINK( elem, pList->Head, pList->FwdLinkOffset);
pList->Head = elem;
// fix up the forward links
ASSIGNLINK( elem, pList->Head, pList->FwdLinkOffset);
pList->Head = elem;
// fix up the backward links
if ( pNext) {
ASSIGNLINK( pNext, elem, pList->BackLinkOffset);
} else
pList->Tail = elem;
ASSIGNLINK( elem, NULL, pList->BackLinkOffset);
// fix up the backward links
if ( pNext) {
ASSIGNLINK( pNext, elem, pList->BackLinkOffset);
} else
pList->Tail = elem;
ASSIGNLINK( elem, NULL, pList->BackLinkOffset);
}
void DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem)
void DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem)
/* Remove a linked list element from the list. */
/* When the element is removed, its link will be set to NULL. */
{
void *pNext, *pPrev;
void *pNext, *pPrev;
pNext = GETLINK( elem, pList->FwdLinkOffset);
pPrev = GETLINK( elem, pList->BackLinkOffset);
pNext = GETLINK( elem, pList->FwdLinkOffset);
pPrev = GETLINK( elem, pList->BackLinkOffset);
// fix up the forward links
if ( pPrev)
ASSIGNLINK( pPrev, pNext, pList->FwdLinkOffset);
else
pList->Head = pNext;
// fix up the backward links
if ( pNext)
ASSIGNLINK( pNext, pPrev, pList->BackLinkOffset);
else
pList->Tail = pPrev;
// fix up the forward links
if ( pPrev)
ASSIGNLINK( pPrev, pNext, pList->FwdLinkOffset);
else
pList->Head = pNext;
ASSIGNLINK( elem, NULL, pList->FwdLinkOffset);
ASSIGNLINK( elem, NULL, pList->BackLinkOffset);
// fix up the backward links
if ( pNext)
ASSIGNLINK( pNext, pPrev, pList->BackLinkOffset);
else
pList->Tail = pPrev;
ASSIGNLINK( elem, NULL, pList->FwdLinkOffset);
ASSIGNLINK( elem, NULL, pList->BackLinkOffset);
}
// GenLinkedOffsetList /////////////////////////////////////////////////////
// Extract the Next offset from element
#define GETOFFSET( e, o) ( *(size_t*)((char*) (e) + (o)) )
#define GETOFFSET( e, o) ( *(size_t*)((char*) (e) + (o)) )
static void AssignOffsetLink( void *elem, void *link, size_t linkOffset);
static void AssignOffsetLink( void *elem, void *link, size_t linkOffset);
static void AssignOffsetLink( void *elem, void *link, size_t linkOffset)
static void AssignOffsetLink( void *elem, void *link, size_t linkOffset)
// Assign link to elem as an offset from elem. Assign 0 to elem if link is NULL.
{
GETOFFSET( elem, linkOffset) = link ? (size_t) link - (size_t) elem : 0;
GETOFFSET( elem, linkOffset) = link ? (size_t) link - (size_t) elem : 0;
}
void *GetHeadPtr( GenLinkedOffsetList *pList)
void *GetHeadPtr( GenLinkedOffsetList *pList)
/* Return a pointer to the head element of a list, or NULL if none. */
{
return pList->Head ? ( (char*) (pList) + pList->Head) : NULL;
return pList->Head ? ( (char*) (pList) + pList->Head) : NULL;
}
void *GetTailPtr( GenLinkedOffsetList *pList)
void *GetTailPtr( GenLinkedOffsetList *pList)
/* Return a pointer to the tail element of a list, or NULL if none. */
{
return pList->Tail ? ( (char*) (pList) + pList->Tail) : NULL;
return pList->Tail ? ( (char*) (pList) + pList->Tail) : NULL;
}
void *GetOffsetLink( GenLinkedOffsetList *pList, void *elem)
void *GetOffsetLink( GenLinkedOffsetList *pList, void *elem)
/* Return the link pointer contained within element e for pList, or NULL if it is 0. */
{
size_t nextOffset;
size_t nextOffset;
nextOffset = GETOFFSET( elem, pList->LinkOffset);
nextOffset = GETOFFSET( elem, pList->LinkOffset);
return nextOffset ? (char*) elem + nextOffset : NULL;
return nextOffset ? (char*) elem + nextOffset : NULL;
}
void InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset)
void InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset)
/* Initialize the block of memory pointed to by pList as a linked list. */
{
pList->Head = 0;
pList->Tail = 0;
pList->LinkOffset = linkOffset;
pList->Head = 0;
pList->Tail = 0;
pList->LinkOffset = linkOffset;
}
void OffsetAddToTail( GenLinkedOffsetList *pList, void *elem)
void OffsetAddToTail( GenLinkedOffsetList *pList, void *elem)
/* Add a linked list element to the tail of the list. */
{
if ( pList->Tail) {
AssignOffsetLink( GetTailPtr( pList), elem, pList->LinkOffset);
} else
pList->Head = (size_t) elem - (size_t) pList;
AssignOffsetLink( elem, NULL, pList->LinkOffset);
if ( pList->Tail) {
AssignOffsetLink( GetTailPtr( pList), elem, pList->LinkOffset);
} else
pList->Head = (size_t) elem - (size_t) pList;
AssignOffsetLink( elem, NULL, pList->LinkOffset);
pList->Tail = (size_t) elem - (size_t) pList;
pList->Tail = (size_t) elem - (size_t) pList;
}
void OffsetAddToHead( GenLinkedOffsetList *pList, void *elem)
void OffsetAddToHead( GenLinkedOffsetList *pList, void *elem)
/* Add a linked list element to the head of the list. */
{
AssignOffsetLink( elem, GetHeadPtr( pList), pList->LinkOffset);
if ( pList->Tail == 0)
pList->Tail = (size_t) elem - (size_t) pList;
AssignOffsetLink( elem, GetHeadPtr( pList), pList->LinkOffset);
if ( pList->Tail == 0)
pList->Tail = (size_t) elem - (size_t) pList;
pList->Head = (size_t) elem - (size_t) pList;
pList->Head = (size_t) elem - (size_t) pList;
}
int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem)
int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem)
/* Remove a linked list element from the list. Return 0 if it was not found. */
/* If the element is removed, its link will be set to NULL. */
{
void *iElem, *lastElem;
void *iElem, *lastElem;
for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
iElem = GetOffsetLink( pList, iElem))
{
if ( iElem == elem) {
if ( lastElem) { // somewhere past the head
AssignOffsetLink( lastElem, GetOffsetLink( pList, elem), pList->LinkOffset);
} else { // at the head
iElem = GetOffsetLink( pList, elem);
pList->Head = iElem ? (size_t) iElem - (size_t) pList : 0;
}
if ( GetTailPtr( pList) == elem)
pList->Tail = lastElem ? (size_t) lastElem - (size_t) pList : 0;
AssignOffsetLink( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug.
return 1;
}
lastElem = iElem;
}
for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
iElem = GetOffsetLink( pList, iElem))
{
if ( iElem == elem) {
if ( lastElem) { // somewhere past the head
AssignOffsetLink( lastElem, GetOffsetLink( pList, elem), pList->LinkOffset);
} else { // at the head
iElem = GetOffsetLink( pList, elem);
pList->Head = iElem ? (size_t) iElem - (size_t) pList : 0;
}
if ( GetTailPtr( pList) == elem)
pList->Tail = lastElem ? (size_t) lastElem - (size_t) pList : 0;
AssignOffsetLink( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug.
return 1;
}
lastElem = iElem;
}
return 0;
return 0;
}
int OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem)
int OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem)
/* Replace an element in the list with a new element, in the same position. */
{
void *iElem, *lastElem;
void *iElem, *lastElem;
if ( elemInList == NULL || newElem == NULL)
return 0;
if ( elemInList == NULL || newElem == NULL)
return 0;
for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
iElem = GetOffsetLink( pList, iElem))
{
if ( iElem == elemInList)
{
AssignOffsetLink( newElem, GetOffsetLink( pList, elemInList), pList->LinkOffset);
if ( lastElem) // somewhere past the head
{
AssignOffsetLink( lastElem, newElem, pList->LinkOffset);
}
else // at the head
{
pList->Head = (size_t) newElem - (size_t) pList;
}
if ( GetTailPtr( pList) == elemInList)
pList->Tail = (size_t) newElem - (size_t) pList;
return 1;
}
lastElem = iElem;
}
for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
iElem = GetOffsetLink( pList, iElem))
{
if ( iElem == elemInList)
{
AssignOffsetLink( newElem, GetOffsetLink( pList, elemInList), pList->LinkOffset);
if ( lastElem) // somewhere past the head
{
AssignOffsetLink( lastElem, newElem, pList->LinkOffset);
}
else // at the head
{
pList->Head = (size_t) newElem - (size_t) pList;
}
if ( GetTailPtr( pList) == elemInList)
pList->Tail = (size_t) newElem - (size_t) pList;
return 1;
}
lastElem = iElem;
}
return 0;
return 0;
}

View File

@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -22,69 +22,69 @@
#include <stddef.h>
struct GenLinkedList
struct GenLinkedList
{
void *Head,
*Tail;
size_t LinkOffset;
void *Head,
*Tail;
size_t LinkOffset;
};
typedef struct GenLinkedList GenLinkedList;
typedef struct GenLinkedList GenLinkedList;
void InitLinkedList( GenLinkedList *pList, size_t linkOffset);
void InitLinkedList( GenLinkedList *pList, size_t linkOffset);
void AddToHead( GenLinkedList *pList, void *elem);
void AddToTail( GenLinkedList *pList, void *elem);
void AddToHead( GenLinkedList *pList, void *elem);
void AddToTail( GenLinkedList *pList, void *elem);
int RemoveFromList( GenLinkedList *pList, void *elem);
int RemoveFromList( GenLinkedList *pList, void *elem);
int ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem);
int ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem);
struct GenDoubleLinkedList
struct GenDoubleLinkedList
{
void *Head,
*Tail;
size_t FwdLinkOffset,
BackLinkOffset;
void *Head,
*Tail;
size_t FwdLinkOffset,
BackLinkOffset;
};
typedef struct GenDoubleLinkedList GenDoubleLinkedList;
typedef struct GenDoubleLinkedList GenDoubleLinkedList;
void InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset,
size_t backLinkOffset);
void InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset,
size_t backLinkOffset);
void DLLAddToHead( GenDoubleLinkedList *pList, void *elem);
void DLLAddToHead( GenDoubleLinkedList *pList, void *elem);
void DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem);
void DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem);
/* A GenLinkedOffsetList is like a GenLinkedList that stores the *Next field as a signed */
/* offset from the address of the beginning of the element, rather than as a pointer. */
struct GenLinkedOffsetList
struct GenLinkedOffsetList
{
size_t Head,
Tail;
size_t LinkOffset;
size_t Head,
Tail;
size_t LinkOffset;
};
typedef struct GenLinkedOffsetList GenLinkedOffsetList;
typedef struct GenLinkedOffsetList GenLinkedOffsetList;
void InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset);
void InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset);
void *GetHeadPtr( GenLinkedOffsetList *pList);
void *GetTailPtr( GenLinkedOffsetList *pList);
void *GetOffsetLink( GenLinkedOffsetList *pList, void *elem);
void *GetHeadPtr( GenLinkedOffsetList *pList);
void *GetTailPtr( GenLinkedOffsetList *pList);
void *GetOffsetLink( GenLinkedOffsetList *pList, void *elem);
void OffsetAddToHead( GenLinkedOffsetList *pList, void *elem);
void OffsetAddToTail( GenLinkedOffsetList *pList, void *elem);
void OffsetAddToHead( GenLinkedOffsetList *pList, void *elem);
void OffsetAddToTail( GenLinkedOffsetList *pList, void *elem);
int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem);
int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem);
int OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem);
int OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem);
#endif // __GenLinkedList__

View File

@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,182 +15,185 @@
* limitations under the License.
*/
#include <stdio.h> // Needed for fopen() etc.
#include <unistd.h> // Needed for close()
#include <string.h> // Needed for strlen() etc.
#include <errno.h> // Needed for errno etc.
#include <sys/socket.h> // Needed for socket() etc.
#include <netinet/in.h> // Needed for sockaddr_in
#include <stdio.h> // Needed for fopen() etc.
#include <unistd.h> // Needed for close()
#include <string.h> // Needed for strlen() etc.
#include <errno.h> // Needed for errno etc.
#include <sys/socket.h> // Needed for socket() etc.
#include <netinet/in.h> // Needed for sockaddr_in
#include <syslog.h>
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "DNSCommon.h"
#include "PlatformCommon.h"
#ifdef NOT_HAVE_SOCKLEN_T
typedef unsigned int socklen_t;
typedef unsigned int socklen_t;
#endif
// Bind a UDP socket to find the source address to a destination
mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
{
union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr;
socklen_t len = sizeof(addr);
socklen_t inner_len = 0;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
src->type = mDNSAddrType_None;
if (sock == -1) return;
if (dst->type == mDNSAddrType_IPv4)
{
inner_len = sizeof(addr.a4);
#ifndef NOT_HAVE_SA_LEN
addr.a4.sin_len = inner_len;
#endif
addr.a4.sin_family = AF_INET;
addr.a4.sin_port = 1; // Not important, any port will do
addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
}
else if (dst->type == mDNSAddrType_IPv6)
{
inner_len = sizeof(addr.a6);
#ifndef NOT_HAVE_SA_LEN
addr.a6.sin6_len = inner_len;
#endif
addr.a6.sin6_family = AF_INET6;
addr.a6.sin6_flowinfo = 0;
addr.a6.sin6_port = 1; // Not important, any port will do
addr.a6.sin6_addr = *(struct in6_addr*)&dst->ip.v6;
addr.a6.sin6_scope_id = 0;
}
else return;
{
union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr;
socklen_t len = sizeof(addr);
socklen_t inner_len = 0;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
src->type = mDNSAddrType_None;
if (sock == -1) return;
if (dst->type == mDNSAddrType_IPv4)
{
inner_len = sizeof(addr.a4);
#ifndef NOT_HAVE_SA_LEN
addr.a4.sin_len = inner_len;
#endif
addr.a4.sin_family = AF_INET;
addr.a4.sin_port = 1; // Not important, any port will do
addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
}
else if (dst->type == mDNSAddrType_IPv6)
{
inner_len = sizeof(addr.a6);
#ifndef NOT_HAVE_SA_LEN
addr.a6.sin6_len = inner_len;
#endif
addr.a6.sin6_family = AF_INET6;
addr.a6.sin6_flowinfo = 0;
addr.a6.sin6_port = 1; // Not important, any port will do
addr.a6.sin6_addr = *(struct in6_addr*)&dst->ip.v6;
addr.a6.sin6_scope_id = 0;
}
else return;
if ((connect(sock, &addr.s, inner_len)) < 0)
{ LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno, strerror(errno)); goto exit; }
if ((connect(sock, &addr.s, inner_len)) < 0)
{ LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno, strerror(errno)); goto exit; }
if ((getsockname(sock, &addr.s, &len)) < 0)
{ LogMsg("mDNSPlatformSourceAddrForDest: getsockname failed errno %d (%s)", errno, strerror(errno)); goto exit; }
if ((getsockname(sock, &addr.s, &len)) < 0)
{ LogMsg("mDNSPlatformSourceAddrForDest: getsockname failed errno %d (%s)", errno, strerror(errno)); goto exit; }
src->type = dst->type;
if (dst->type == mDNSAddrType_IPv4) src->ip.v4.NotAnInteger = addr.a4.sin_addr.s_addr;
else src->ip.v6 = *(mDNSv6Addr*)&addr.a6.sin6_addr;
src->type = dst->type;
if (dst->type == mDNSAddrType_IPv4) src->ip.v4.NotAnInteger = addr.a4.sin_addr.s_addr;
else src->ip.v6 = *(mDNSv6Addr*)&addr.a6.sin6_addr;
exit:
close(sock);
}
close(sock);
}
// dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length
mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
{
char buf[32+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value
unsigned int len = strlen(option);
if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; }
fseek(f, 0, SEEK_SET); // set position to beginning of stream
while (fgets(buf, sizeof(buf), f)) // Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator
{
if (!strncmp(buf, option, len))
{
strncpy(dst, buf + len + 1, MAX_ESCAPED_DOMAIN_NAME-1);
if (dst[MAX_ESCAPED_DOMAIN_NAME-1]) dst[MAX_ESCAPED_DOMAIN_NAME-1] = '\0';
len = strlen(dst);
if (len && dst[len-1] == '\n') dst[len-1] = '\0'; // chop newline
return mDNStrue;
}
}
debugf("Option %s not set", option);
return mDNSfalse;
}
{
char buf[32+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value
unsigned int len = strlen(option);
if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; }
fseek(f, 0, SEEK_SET); // set position to beginning of stream
while (fgets(buf, sizeof(buf), f)) // Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator
{
if (!strncmp(buf, option, len))
{
strncpy(dst, buf + len + 1, MAX_ESCAPED_DOMAIN_NAME-1);
if (dst[MAX_ESCAPED_DOMAIN_NAME-1]) dst[MAX_ESCAPED_DOMAIN_NAME-1] = '\0';
len = strlen(dst);
if (len && dst[len-1] == '\n') dst[len-1] = '\0'; // chop newline
return mDNStrue;
}
}
debugf("Option %s not set", option);
return mDNSfalse;
}
mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled)
{
char buf[MAX_ESCAPED_DOMAIN_NAME] = "";
mStatus err;
FILE *f = fopen(filename, "r");
{
char buf[MAX_ESCAPED_DOMAIN_NAME] = "";
mStatus err;
FILE *f = fopen(filename, "r");
if (hostname) hostname->c[0] = 0;
if (domain) domain->c[0] = 0;
if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse;
if (hostname) hostname->c[0] = 0;
if (domain) domain->c[0] = 0;
if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse;
if (f)
{
if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue;
if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf;
if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf;
buf[0] = 0;
GetConfigOption(buf, "secret-64", f); // failure means no authentication
fclose(f);
f = NULL;
}
else
{
if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened.");
return;
}
if (f)
{
if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue;
if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf;
if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf;
buf[0] = 0;
GetConfigOption(buf, "secret-64", f); // failure means no authentication
fclose(f);
f = NULL;
}
else
{
if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened.");
return;
}
if (domain && domain->c[0] && buf[0])
{
DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
// for now we assume keyname = service reg domain and we use same key for service and hostname registration
err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, NULL);
if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
}
if (domain && domain->c[0] && buf[0])
{
DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
// for now we assume keyname = service reg domain and we use same key for service and hostname registration
err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, mDNSfalse);
if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
}
return;
return;
badf:
LogMsg("ERROR: malformatted config file");
if (f) fclose(f);
}
badf:
LogMsg("ERROR: malformatted config file");
if (f) fclose(f);
}
#if MDNS_DEBUGMSGS
mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
{
fprintf(stderr,"%s\n", msg);
fflush(stderr);
}
{
fprintf(stderr,"%s\n", msg);
fflush(stderr);
}
#endif
mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel)
{
{
#if APPLE_OSX_mDNSResponder && LogTimeStamps
extern mDNS mDNSStorage;
extern mDNSu32 mDNSPlatformClockDivisor;
mDNSs32 t = mDNSStorage.timenow ? mDNSStorage.timenow : mDNSPlatformClockDivisor ? mDNS_TimeNow_NoLock(&mDNSStorage) : 0;
int ms = ((t < 0) ? -t : t) % 1000;
extern mDNS mDNSStorage;
extern mDNSu32 mDNSPlatformClockDivisor;
mDNSs32 t = mDNSStorage.timenow ? mDNSStorage.timenow : mDNSPlatformClockDivisor ? mDNS_TimeNow_NoLock(&mDNSStorage) : 0;
int ms = ((t < 0) ? -t : t) % 1000;
#endif
if (mDNS_DebugMode) // In debug mode we write to stderr
{
if (mDNS_DebugMode) // In debug mode we write to stderr
{
#if APPLE_OSX_mDNSResponder && LogTimeStamps
if (ident && ident[0] && mDNSPlatformClockDivisor)
fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer);
else
if (ident && ident[0] && mDNSPlatformClockDivisor)
fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer);
else
#endif
fprintf(stderr,"%s\n", buffer);
fflush(stderr);
}
else // else, in production mode, we write to syslog
{
static int log_inited = 0;
int syslog_level = LOG_ERR;
switch (loglevel)
{
case MDNS_LOG_MSG: syslog_level = LOG_ERR; break;
case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break;
case MDNS_LOG_SPS: syslog_level = LOG_NOTICE; break;
case MDNS_LOG_INFO: syslog_level = LOG_INFO; break;
case MDNS_LOG_DEBUG: syslog_level = LOG_DEBUG; break;
default:
fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
fflush(stderr);
}
if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
fprintf(stderr,"%s\n", buffer);
fflush(stderr);
}
else // else, in production mode, we write to syslog
{
static int log_inited = 0;
int syslog_level = LOG_ERR;
switch (loglevel)
{
case MDNS_LOG_MSG: syslog_level = LOG_ERR; break;
case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break;
case MDNS_LOG_SPS: syslog_level = LOG_NOTICE; break;
case MDNS_LOG_INFO: syslog_level = LOG_INFO; break;
case MDNS_LOG_DEBUG: syslog_level = LOG_DEBUG; break;
default:
fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
fflush(stderr);
}
if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
#if APPLE_OSX_mDNSResponder && LogTimeStamps
if (ident && ident[0] && mDNSPlatformClockDivisor)
syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer);
else
if (ident && ident[0] && mDNSPlatformClockDivisor)
syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer);
else
#elif APPLE_OSX_mDNSResponder
mDNSPlatformLogToFile(syslog_level, buffer);
#else
syslog(syslog_level, "%s", buffer);
#endif
syslog(syslog_level, "%s", buffer);
}
}
}
}

View File

@ -5,9 +5,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -16,18 +16,32 @@
.\"
.Dd April 2004 \" Date
.Dt dns-sd 1 \" Document Title
.Os NetBSD \" Operating System
.Os Darwin \" Operating System
.\"
.Sh NAME
.Nm dns-sd
.Nd Multicast DNS (mDNS) & DNS Service Discovery (DNS-SD) Test Tool \" For whatis
.\"
.Sh SYNOPSIS
.Nm Fl E
.Pp
.Nm Fl F
.Pp
.Nm Fl R Ar name type domain port Op Ar key=value ...
.Pp
.Nm Fl B Ar type domain
.Pp
.Nm Fl L Ar name type domain
.Pp
.Nm Fl P Ar name type domain port host IP Op Ar key=value ...
.Pp
.Nm Fl q Ar name rrtype rrclass
.Pp
.Nm Fl Z Ar type domain
.Pp
.Nm Fl G Ns \ v4/v6/v4v6 Ar name
.Pp
.Nm Fl V
.\"
.Sh DESCRIPTION
The
@ -43,6 +57,11 @@ The library API that
.Nm
uses is documented in
.Pa /usr/include/dns_sd.h .
The
.Nm
command replaces the older
mDNS
command.
.Pp
The
.Nm
@ -73,7 +92,17 @@ directly call DNS-SD APIs using the dnssd package documented at
.br
Similar bindings for other languages are also in development.
.Pp
.Bl -tag -width R
.Bl -tag -width E
.It Nm Fl E
return a list of domains recommended for registering(advertising) services.
.Pp
.It Nm Fl F
return a list of domains recommended for browsing services.
.Pp
Normally, on your home network, the only domain you are likely to see is "local".
However if your network administrator has created Domain Enumeration records,
then you may also see other recommended domains for registering and browsing.
.Pp
.It Nm Fl R Ar name type domain port Op Ar key=value ...
register (advertise) a service in the specified
.Ar domain
@ -91,7 +120,7 @@ up to 63 UTF-8 bytes long.
.Ar type
must be of the form "_app-proto._tcp" or "_app-proto._udp", where
"app-proto" is an application protocol name registered at
.Pa http://www.dns-sd.org/ServiceTypes.html .
.Pa http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml .
.Pp
.Ar domain
is the domain in which to register the service.
@ -110,7 +139,7 @@ Additional attributes of the service may optionally be described by
key/value pairs, which are stored in the advertised service's DNS TXT
record. Allowable keys and values are listed with the service
registration at
.Pa http://www.dns-sd.org/ServiceTypes.html .
.Pa http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml .
.It Nm Fl B Ar type domain
browse for instances of service
.Ar type
@ -120,7 +149,7 @@ in
For valid
.Ar type Ns s
see
.Pa http://www.dns-sd.org/ServiceTypes.html
.Pa http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml .
as described above. Omitting the
.Ar domain
or using "." means "pick a sensible default."
@ -130,12 +159,39 @@ named service: the hostname of the machine where that service is
available, the port number on which the service is listening, and (if
present) TXT record attributes describing properties of the service.
.Pp
Note that in a typical application, browsing happens rarely, while lookup
Note that in a typical application, browsing may only happen rarely, while lookup
(or "resolving") happens every time the service is used. For example, a
user browses the network to pick a default printer fairly rarely, but once
a default printer has been picked, that named service is resolved to its
current IP address and port number every time the user presses Cmd-P to
print.
.Pp
.It Nm Fl P Ar name type domain port host IP Op Ar key=value ...
create a proxy advertisement for a service running on(offered by) some other machine.
The two new options are Host, a name for the device and IP, the address of it.
.Pp
The service for which you create a proxy advertisement does not necessarily have to be on your local network.
You can set up a local proxy for a website on the Internet.
.Pp
.It Nm Fl q Ar name rrtype rrclass
look up any DNS name, resource record type, and resource record class,
not necessarily DNS-SD names and record types.
If rrtype is not specified, it queries for the IPv4 address of the name,
if rrclass is not specified, IN class is assumed. If the name is not a fully
qualified domain name, then search domains may be appended.
.Pp
.It Nm Fl Z Ar type domain
browse for service instances and display output in zone file format.
.Pp
.It Nm Fl G Ns \ v4/v6/v4v6 Ar name
look up the IP address information of the name.
If v4 is specified, the IPv4 address of the name is looked up,
if v6 is specified the IPv6 address is looked up. If v4v6 is specified both the IPv4 and IPv6
address is looked up. If the name is not a fully qualified domain name,
then search domains may be appended.
.Pp
.It Nm Fl V
return the version of the currently running daemon/system service.
.El
.Sh EXAMPLES
.Pp
@ -172,15 +228,39 @@ window and you should see the "Remove" event reported to the
.Nm Fl B
window.
.Pp
In the example below, the www.apple.com web page is advertised as a service called "apple",
running on a target host called apple.local, which resolves to 17.149.160.49.
.Pp
.Dl Nm Fl P Ns \ apple _http._tcp \&"\&"\& 80 apple.local 17.149.160.49
.Pp
The Bonjour menu in the Safari web browser will now show "apple".
The same IP address can be reached by entering apple.local in the web browser.
In either case, the request will be resolved to the IP address and browser will show
contents associated with www.apple.com.
.Pp
If a client wants to be notified of changes in server state, it can
initiate a query for the service's particular record and leave it running.
For example, to monitor the status of an iChat user you can use:
.Pp
.Dl Nm Fl q Ns \ someone@ex1._presence._tcp.local txt
.Pp
Everytime status of that user(someone) changes, you will see a new TXT record result reported.
.Pp
You can also query for a unicast name like www.apple.com and monitor its status.
.Pp
.Dl Nm Fl q Ns \ www.apple.com
.Pp
.Sh FILES
.Pa /usr/bin/dns-sd \" Pathname
.\"
.Sh SEE ALSO
.Xr mdnsd 8
.Xr mDNSResponder 8
.\"
.Sh BUGS
.Nm
bugs are tracked in Apple Radar component "mDNSResponder".
.\"
.Sh HISTORY
The
.Nm
command first appeared in
.Nx 6.0 ,
having originated in Mac OS X 10.4 (Tiger).
command first appeared in Mac OS X 10.4 (Tiger).

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,585 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mDNSEmbeddedAPI.h"
#include "DebugServices.h"
#include "dnsextd.h"
void yyerror( const char* error );
int yylex(void);
typedef struct StringListElem
{
char * string;
struct StringListElem * next;
} StringListElem;
typedef struct OptionsInfo
{
char server_address[ 256 ];
int server_port;
char source_address[ 256 ];
int source_port;
int private_port;
int llq_port;
} OptionsInfo;
typedef struct ZoneInfo
{
char name[ 256 ];
char certificate_name[ 256 ];
char allow_clients_file[ 256 ];
char allow_clients[ 256 ];
char key[ 256 ];
} ZoneInfo;
typedef struct KeySpec
{
char name[ 256 ];
char algorithm[ 256 ];
char secret[ 256 ];
struct KeySpec * next;
} KeySpec;
typedef struct ZoneSpec
{
char name[ 256 ];
DNSZoneSpecType type;
StringListElem * allowUpdate;
StringListElem * allowQuery;
char key[ 256 ];
struct ZoneSpec * next;
} ZoneSpec;
static StringListElem * g_stringList = NULL;
static KeySpec * g_keys;
static ZoneSpec * g_zones;
static ZoneSpec g_zoneSpec;
static const char * g_filename;
#define YYPARSE_PARAM context
void
SetupOptions
(
OptionsInfo * info,
void * context
);
%}
%union
{
int number;
char * string;
}
%token OPTIONS
%token LISTEN_ON
%token NAMESERVER
%token PORT
%token ADDRESS
%token LLQ
%token PUBLIC
%token PRIVATE
%token ALLOWUPDATE
%token ALLOWQUERY
%token KEY
%token ALGORITHM
%token SECRET
%token ISSUER
%token SERIAL
%token ZONE
%token TYPE
%token ALLOW
%token OBRACE
%token EBRACE
%token SEMICOLON
%token IN
%token <string> DOTTED_DECIMAL_ADDRESS
%token <string> WILDCARD
%token <string> DOMAINNAME
%token <string> HOSTNAME
%token <string> QUOTEDSTRING
%token <number> NUMBER
%type <string> addressstatement
%type <string> networkaddress
%%
commands:
|
commands command SEMICOLON
;
command:
options_set
|
zone_set
|
key_set
;
options_set:
OPTIONS optionscontent
{
// SetupOptions( &g_optionsInfo, context );
}
;
optionscontent:
OBRACE optionsstatements EBRACE
;
optionsstatements:
|
optionsstatements optionsstatement SEMICOLON
;
optionsstatement:
statements
|
LISTEN_ON addresscontent
{
}
|
LISTEN_ON PORT NUMBER addresscontent
{
}
|
NAMESERVER ADDRESS networkaddress
{
}
|
NAMESERVER ADDRESS networkaddress PORT NUMBER
{
}
|
PRIVATE PORT NUMBER
{
( ( DaemonInfo* ) context )->private_port = mDNSOpaque16fromIntVal( $3 );
}
|
LLQ PORT NUMBER
{
( ( DaemonInfo* ) context )->llq_port = mDNSOpaque16fromIntVal( $3 );
}
;
key_set:
KEY QUOTEDSTRING OBRACE SECRET QUOTEDSTRING SEMICOLON EBRACE
{
KeySpec * keySpec;
keySpec = ( KeySpec* ) malloc( sizeof( KeySpec ) );
if ( !keySpec )
{
LogMsg("ERROR: memory allocation failure");
YYABORT;
}
strncpy( keySpec->name, $2, sizeof( keySpec->name ) );
strncpy( keySpec->secret, $5, sizeof( keySpec->secret ) );
keySpec->next = g_keys;
g_keys = keySpec;
}
;
zone_set:
ZONE QUOTEDSTRING zonecontent
{
ZoneSpec * zoneSpec;
zoneSpec = ( ZoneSpec* ) malloc( sizeof( ZoneSpec ) );
if ( !zoneSpec )
{
LogMsg("ERROR: memory allocation failure");
YYABORT;
}
strncpy( zoneSpec->name, $2, sizeof( zoneSpec->name ) );
zoneSpec->type = g_zoneSpec.type;
strcpy( zoneSpec->key, g_zoneSpec.key );
zoneSpec->allowUpdate = g_zoneSpec.allowUpdate;
zoneSpec->allowQuery = g_zoneSpec.allowQuery;
zoneSpec->next = g_zones;
g_zones = zoneSpec;
}
|
ZONE QUOTEDSTRING IN zonecontent
{
ZoneSpec * zoneSpec;
zoneSpec = ( ZoneSpec* ) malloc( sizeof( ZoneSpec ) );
if ( !zoneSpec )
{
LogMsg("ERROR: memory allocation failure");
YYABORT;
}
strncpy( zoneSpec->name, $2, sizeof( zoneSpec->name ) );
zoneSpec->type = g_zoneSpec.type;
strcpy( zoneSpec->key, g_zoneSpec.key );
zoneSpec->allowUpdate = g_zoneSpec.allowUpdate;
zoneSpec->allowQuery = g_zoneSpec.allowQuery;
zoneSpec->next = g_zones;
g_zones = zoneSpec;
}
;
zonecontent:
OBRACE zonestatements EBRACE
zonestatements:
|
zonestatements zonestatement SEMICOLON
;
zonestatement:
TYPE PUBLIC
{
g_zoneSpec.type = kDNSZonePublic;
}
|
TYPE PRIVATE
{
g_zoneSpec.type = kDNSZonePrivate;
}
|
ALLOWUPDATE keycontent
{
g_zoneSpec.allowUpdate = g_stringList;
g_stringList = NULL;
}
|
ALLOWQUERY keycontent
{
g_zoneSpec.allowQuery = g_stringList;
g_stringList = NULL;
}
;
addresscontent:
OBRACE addressstatements EBRACE
{
}
addressstatements:
|
addressstatements addressstatement SEMICOLON
{
}
;
addressstatement:
DOTTED_DECIMAL_ADDRESS
{
}
;
keycontent:
OBRACE keystatements EBRACE
{
}
keystatements:
|
keystatements keystatement SEMICOLON
{
}
;
keystatement:
KEY DOMAINNAME
{
StringListElem * elem;
elem = ( StringListElem* ) malloc( sizeof( StringListElem ) );
if ( !elem )
{
LogMsg("ERROR: memory allocation failure");
YYABORT;
}
elem->string = $2;
elem->next = g_stringList;
g_stringList = elem;
}
;
networkaddress:
DOTTED_DECIMAL_ADDRESS
|
HOSTNAME
|
WILDCARD
;
block:
OBRACE zonestatements EBRACE SEMICOLON
;
statements:
|
statements statement
;
statement:
block
{
$<string>$ = NULL;
}
|
QUOTEDSTRING
{
$<string>$ = $1;
}
%%
int yywrap(void);
extern int yylineno;
void yyerror( const char *str )
{
fprintf( stderr,"%s:%d: error: %s\n", g_filename, yylineno, str );
}
int yywrap()
{
return 1;
}
int
ParseConfig
(
DaemonInfo * d,
const char * file
)
{
extern FILE * yyin;
DNSZone * zone;
DomainAuthInfo * key;
KeySpec * keySpec;
ZoneSpec * zoneSpec;
int err = 0;
g_filename = file;
// Tear down the current zone specifiers
zone = d->zones;
while ( zone )
{
DNSZone * next = zone->next;
key = zone->updateKeys;
while ( key )
{
DomainAuthInfo * nextKey = key->next;
free( key );
key = nextKey;
}
key = zone->queryKeys;
while ( key )
{
DomainAuthInfo * nextKey = key->next;
free( key );
key = nextKey;
}
free( zone );
zone = next;
}
d->zones = NULL;
yyin = fopen( file, "r" );
require_action( yyin, exit, err = 0 );
err = yyparse( ( void* ) d );
require_action( !err, exit, err = 1 );
for ( zoneSpec = g_zones; zoneSpec; zoneSpec = zoneSpec->next )
{
StringListElem * elem;
mDNSu8 * ok;
zone = ( DNSZone* ) malloc( sizeof( DNSZone ) );
require_action( zone, exit, err = 1 );
memset( zone, 0, sizeof( DNSZone ) );
zone->next = d->zones;
d->zones = zone;
// Fill in the domainname
ok = MakeDomainNameFromDNSNameString( &zone->name, zoneSpec->name );
require_action( ok, exit, err = 1 );
// Fill in the type
zone->type = zoneSpec->type;
// Fill in the allow-update keys
for ( elem = zoneSpec->allowUpdate; elem; elem = elem->next )
{
mDNSBool found = mDNSfalse;
for ( keySpec = g_keys; keySpec; keySpec = keySpec->next )
{
if ( strcmp( elem->string, keySpec->name ) == 0 )
{
DomainAuthInfo * authInfo = malloc( sizeof( DomainAuthInfo ) );
mDNSs32 keylen;
require_action( authInfo, exit, err = 1 );
memset( authInfo, 0, sizeof( DomainAuthInfo ) );
ok = MakeDomainNameFromDNSNameString( &authInfo->keyname, keySpec->name );
if (!ok) { free(authInfo); err = 1; goto exit; }
keylen = DNSDigest_ConstructHMACKeyfromBase64( authInfo, keySpec->secret );
if (keylen < 0) { free(authInfo); err = 1; goto exit; }
authInfo->next = zone->updateKeys;
zone->updateKeys = authInfo;
found = mDNStrue;
break;
}
}
// Log this
require_action( found, exit, err = 1 );
}
// Fill in the allow-query keys
for ( elem = zoneSpec->allowQuery; elem; elem = elem->next )
{
mDNSBool found = mDNSfalse;
for ( keySpec = g_keys; keySpec; keySpec = keySpec->next )
{
if ( strcmp( elem->string, keySpec->name ) == 0 )
{
DomainAuthInfo * authInfo = malloc( sizeof( DomainAuthInfo ) );
mDNSs32 keylen;
require_action( authInfo, exit, err = 1 );
memset( authInfo, 0, sizeof( DomainAuthInfo ) );
ok = MakeDomainNameFromDNSNameString( &authInfo->keyname, keySpec->name );
if (!ok) { free(authInfo); err = 1; goto exit; }
keylen = DNSDigest_ConstructHMACKeyfromBase64( authInfo, keySpec->secret );
if (keylen < 0) { free(authInfo); err = 1; goto exit; }
authInfo->next = zone->queryKeys;
zone->queryKeys = authInfo;
found = mDNStrue;
break;
}
}
// Log this
require_action( found, exit, err = 1 );
}
}
exit:
return err;
}
void
SetupOptions
(
OptionsInfo * info,
void * context
)
{
DaemonInfo * d = ( DaemonInfo* ) context;
if ( strlen( info->source_address ) )
{
inet_pton( AF_INET, info->source_address, &d->addr.sin_addr );
}
if ( info->source_port )
{
d->addr.sin_port = htons( ( mDNSu16 ) info->source_port );
}
if ( strlen( info->server_address ) )
{
inet_pton( AF_INET, info->server_address, &d->ns_addr.sin_addr );
}
if ( info->server_port )
{
d->ns_addr.sin_port = htons( ( mDNSu16 ) info->server_port );
}
if ( info->private_port )
{
d->private_port = mDNSOpaque16fromIntVal( info->private_port );
}
if ( info->llq_port )
{
d->llq_port = mDNSOpaque16fromIntVal( info->llq_port );
}
}

View File

@ -2,27 +2,27 @@
*
* Copyright (c) 2004, Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@ -39,14 +39,14 @@
// disable warning "conversion from <data> to uint16_t"
#pragma warning(disable:4244)
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#define strcasecmp _stricmp
#endif
/*********************************************************************************************
*
* Supporting Functions
*
*********************************************************************************************/
*
* Supporting Functions
*
*********************************************************************************************/
#define mDNSIsDigit(X) ((X) >= '0' && (X) <= '9')
@ -54,313 +54,313 @@
// (DNSServiceConstructFullName depends this returning 1 for true, rather than any non-zero value meaning true)
static int DomainEndsInDot(const char *dom)
{
while (dom[0] && dom[1])
{
if (dom[0] == '\\') // advance past escaped byte sequence
{
if (mDNSIsDigit(dom[1]) && mDNSIsDigit(dom[2]) && mDNSIsDigit(dom[3]))
dom += 4; // If "\ddd" then skip four
else dom += 2; // else if "\x" then skip two
}
else dom++; // else goto next character
}
return (dom[0] == '.');
}
{
while (dom[0] && dom[1])
{
if (dom[0] == '\\') // advance past escaped byte sequence
{
if (mDNSIsDigit(dom[1]) && mDNSIsDigit(dom[2]) && mDNSIsDigit(dom[3]))
dom += 4; // If "\ddd" then skip four
else dom += 2; // else if "\x" then skip two
}
else dom++; // else goto next character
}
return (dom[0] == '.');
}
static uint8_t *InternalTXTRecordSearch
(
uint16_t txtLen,
const void *txtRecord,
const char *key,
unsigned long *keylen
)
{
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
*keylen = (unsigned long) strlen(key);
while (p<e)
{
uint8_t *x = p;
p += 1 + p[0];
if (p <= e && *keylen <= x[0] && !strncasecmp(key, (char*)x+1, *keylen))
if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
}
return(NULL);
}
(
uint16_t txtLen,
const void *txtRecord,
const char *key,
unsigned long *keylen
)
{
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
*keylen = (unsigned long) strlen(key);
while (p<e)
{
uint8_t *x = p;
p += 1 + p[0];
if (p <= e && *keylen <= x[0] && !strncasecmp(key, (char*)x+1, *keylen))
if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
}
return(NULL);
}
/*********************************************************************************************
*
* General Utility Functions
*
*********************************************************************************************/
*
* General Utility Functions
*
*********************************************************************************************/
// Note: Need to make sure we don't write more than kDNSServiceMaxDomainName (1009) bytes to fullName
// In earlier builds this constant was defined to be 1005, so to avoid buffer overruns on clients
// compiled with that constant we'll actually limit the output to 1005 bytes.
DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
(
char *const fullName,
const char *const service, // May be NULL
const char *const regtype,
const char *const domain
)
{
const size_t len = !regtype ? 0 : strlen(regtype) - DomainEndsInDot(regtype);
char *fn = fullName;
char *const lim = fullName + 1005;
const char *s = service;
const char *r = regtype;
const char *d = domain;
(
char *const fullName,
const char *const service, // May be NULL
const char *const regtype,
const char *const domain
)
{
const size_t len = !regtype ? 0 : strlen(regtype) - DomainEndsInDot(regtype);
char *fn = fullName;
char *const lim = fullName + 1005;
const char *s = service;
const char *r = regtype;
const char *d = domain;
// regtype must be at least "x._udp" or "x._tcp"
if (len < 6 || !domain || !domain[0]) return kDNSServiceErr_BadParam;
if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return kDNSServiceErr_BadParam;
// regtype must be at least "x._udp" or "x._tcp"
if (len < 6 || !domain || !domain[0]) return kDNSServiceErr_BadParam;
if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return kDNSServiceErr_BadParam;
if (service && *service)
{
while (*s)
{
unsigned char c = *s++; // Needs to be unsigned, or values like 0xFF will be interpreted as < 32
if (c <= ' ') // Escape non-printable characters
{
if (fn+4 >= lim) goto fail;
*fn++ = '\\';
*fn++ = '0' + (c / 100);
*fn++ = '0' + (c / 10) % 10;
c = '0' + (c ) % 10;
}
else if (c == '.' || (c == '\\')) // Escape dot and backslash literals
{
if (fn+2 >= lim) goto fail;
*fn++ = '\\';
}
else
if (fn+1 >= lim) goto fail;
*fn++ = (char)c;
}
*fn++ = '.';
}
if (service && *service)
{
while (*s)
{
unsigned char c = *s++; // Needs to be unsigned, or values like 0xFF will be interpreted as < 32
if (c <= ' ') // Escape non-printable characters
{
if (fn+4 >= lim) goto fail;
*fn++ = '\\';
*fn++ = '0' + (c / 100);
*fn++ = '0' + (c / 10) % 10;
c = '0' + (c ) % 10;
}
else if (c == '.' || (c == '\\')) // Escape dot and backslash literals
{
if (fn+2 >= lim) goto fail;
*fn++ = '\\';
}
else
if (fn+1 >= lim) goto fail;
*fn++ = (char)c;
}
*fn++ = '.';
}
while (*r) if (fn+1 >= lim) goto fail; else *fn++ = *r++;
if (!DomainEndsInDot(regtype)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; }
while (*r) if (fn+1 >= lim) goto fail;else *fn++ = *r++;
if (!DomainEndsInDot(regtype)) { if (fn+1 >= lim) goto fail;else *fn++ = '.';}
while (*d) if (fn+1 >= lim) goto fail; else *fn++ = *d++;
if (!DomainEndsInDot(domain)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; }
while (*d) if (fn+1 >= lim) goto fail;else *fn++ = *d++;
if (!DomainEndsInDot(domain)) { if (fn+1 >= lim) goto fail;else *fn++ = '.';}
*fn = '\0';
return kDNSServiceErr_NoError;
*fn = '\0';
return kDNSServiceErr_NoError;
fail:
*fn = '\0';
return kDNSServiceErr_BadParam;
}
*fn = '\0';
return kDNSServiceErr_BadParam;
}
/*********************************************************************************************
*
* TXT Record Construction Functions
*
*********************************************************************************************/
*
* TXT Record Construction Functions
*
*********************************************************************************************/
typedef struct _TXTRecordRefRealType
{
uint8_t *buffer; // Pointer to data
uint16_t buflen; // Length of buffer
uint16_t datalen; // Length currently in use
uint16_t malloced; // Non-zero if buffer was allocated via malloc()
} TXTRecordRefRealType;
{
uint8_t *buffer; // Pointer to data
uint16_t buflen; // Length of buffer
uint16_t datalen; // Length currently in use
uint16_t malloced; // Non-zero if buffer was allocated via malloc()
} TXTRecordRefRealType;
#define txtRec ((TXTRecordRefRealType*)txtRecord)
// The opaque storage defined in the public dns_sd.h header is 16 bytes;
// make sure we don't exceed that.
struct CompileTimeAssertionCheck_dnssd_clientlib
{
char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1];
};
{
char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1];
};
void DNSSD_API TXTRecordCreate
(
TXTRecordRef *txtRecord,
uint16_t bufferLen,
void *buffer
)
{
txtRec->buffer = buffer;
txtRec->buflen = buffer ? bufferLen : (uint16_t)0;
txtRec->datalen = 0;
txtRec->malloced = 0;
}
(
TXTRecordRef *txtRecord,
uint16_t bufferLen,
void *buffer
)
{
txtRec->buffer = buffer;
txtRec->buflen = buffer ? bufferLen : (uint16_t)0;
txtRec->datalen = 0;
txtRec->malloced = 0;
}
void DNSSD_API TXTRecordDeallocate(TXTRecordRef *txtRecord)
{
if (txtRec->malloced) free(txtRec->buffer);
}
{
if (txtRec->malloced) free(txtRec->buffer);
}
DNSServiceErrorType DNSSD_API TXTRecordSetValue
(
TXTRecordRef *txtRecord,
const char *key,
uint8_t valueSize,
const void *value
)
{
uint8_t *start, *p;
const char *k;
unsigned long keysize, keyvalsize;
(
TXTRecordRef *txtRecord,
const char *key,
uint8_t valueSize,
const void *value
)
{
uint8_t *start, *p;
const char *k;
unsigned long keysize, keyvalsize;
for (k = key; *k; k++) if (*k < 0x20 || *k > 0x7E || *k == '=') return(kDNSServiceErr_Invalid);
keysize = (unsigned long)(k - key);
keyvalsize = 1 + keysize + (value ? (1 + valueSize) : 0);
if (keysize < 1 || keyvalsize > 255) return(kDNSServiceErr_Invalid);
(void)TXTRecordRemoveValue(txtRecord, key);
if (txtRec->datalen + keyvalsize > txtRec->buflen)
{
unsigned char *newbuf;
unsigned long newlen = txtRec->datalen + keyvalsize;
if (newlen > 0xFFFF) return(kDNSServiceErr_Invalid);
newbuf = malloc((size_t)newlen);
if (!newbuf) return(kDNSServiceErr_NoMemory);
memcpy(newbuf, txtRec->buffer, txtRec->datalen);
if (txtRec->malloced) free(txtRec->buffer);
txtRec->buffer = newbuf;
txtRec->buflen = (uint16_t)(newlen);
txtRec->malloced = 1;
}
start = txtRec->buffer + txtRec->datalen;
p = start + 1;
memcpy(p, key, keysize);
p += keysize;
if (value)
{
*p++ = '=';
memcpy(p, value, valueSize);
p += valueSize;
}
*start = (uint8_t)(p - start - 1);
txtRec->datalen += p - start;
return(kDNSServiceErr_NoError);
}
for (k = key; *k; k++) if (*k < 0x20 || *k > 0x7E || *k == '=') return(kDNSServiceErr_Invalid);
keysize = (unsigned long)(k - key);
keyvalsize = 1 + keysize + (value ? (1 + valueSize) : 0);
if (keysize < 1 || keyvalsize > 255) return(kDNSServiceErr_Invalid);
(void)TXTRecordRemoveValue(txtRecord, key);
if (txtRec->datalen + keyvalsize > txtRec->buflen)
{
unsigned char *newbuf;
unsigned long newlen = txtRec->datalen + keyvalsize;
if (newlen > 0xFFFF) return(kDNSServiceErr_Invalid);
newbuf = malloc((size_t)newlen);
if (!newbuf) return(kDNSServiceErr_NoMemory);
memcpy(newbuf, txtRec->buffer, txtRec->datalen);
if (txtRec->malloced) free(txtRec->buffer);
txtRec->buffer = newbuf;
txtRec->buflen = (uint16_t)(newlen);
txtRec->malloced = 1;
}
start = txtRec->buffer + txtRec->datalen;
p = start + 1;
memcpy(p, key, keysize);
p += keysize;
if (value)
{
*p++ = '=';
memcpy(p, value, valueSize);
p += valueSize;
}
*start = (uint8_t)(p - start - 1);
txtRec->datalen += p - start;
return(kDNSServiceErr_NoError);
}
DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
(
TXTRecordRef *txtRecord,
const char *key
)
{
unsigned long keylen, itemlen, remainder;
uint8_t *item = InternalTXTRecordSearch(txtRec->datalen, txtRec->buffer, key, &keylen);
if (!item) return(kDNSServiceErr_NoSuchKey);
itemlen = (unsigned long)(1 + item[0]);
remainder = (unsigned long)((txtRec->buffer + txtRec->datalen) - (item + itemlen));
// Use memmove because memcpy behaviour is undefined for overlapping regions
memmove(item, item + itemlen, remainder);
txtRec->datalen -= itemlen;
return(kDNSServiceErr_NoError);
}
(
TXTRecordRef *txtRecord,
const char *key
)
{
unsigned long keylen, itemlen, remainder;
uint8_t *item = InternalTXTRecordSearch(txtRec->datalen, txtRec->buffer, key, &keylen);
if (!item) return(kDNSServiceErr_NoSuchKey);
itemlen = (unsigned long)(1 + item[0]);
remainder = (unsigned long)((txtRec->buffer + txtRec->datalen) - (item + itemlen));
// Use memmove because memcpy behaviour is undefined for overlapping regions
memmove(item, item + itemlen, remainder);
txtRec->datalen -= itemlen;
return(kDNSServiceErr_NoError);
}
uint16_t DNSSD_API TXTRecordGetLength (const TXTRecordRef *txtRecord) { return(txtRec->datalen); }
const void * DNSSD_API TXTRecordGetBytesPtr(const TXTRecordRef *txtRecord) { return(txtRec->buffer); }
/*********************************************************************************************
*
* TXT Record Parsing Functions
*
*********************************************************************************************/
*
* TXT Record Parsing Functions
*
*********************************************************************************************/
int DNSSD_API TXTRecordContainsKey
(
uint16_t txtLen,
const void *txtRecord,
const char *key
)
{
unsigned long keylen;
return (InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen) ? 1 : 0);
}
(
uint16_t txtLen,
const void *txtRecord,
const char *key
)
{
unsigned long keylen;
return (InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen) ? 1 : 0);
}
const void * DNSSD_API TXTRecordGetValuePtr
(
uint16_t txtLen,
const void *txtRecord,
const char *key,
uint8_t *valueLen
)
{
unsigned long keylen;
uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen);
if (!item || item[0] <= keylen) return(NULL); // If key not found, or found with no value, return NULL
*valueLen = (uint8_t)(item[0] - (keylen + 1));
return (item + 1 + keylen + 1);
}
(
uint16_t txtLen,
const void *txtRecord,
const char *key,
uint8_t *valueLen
)
{
unsigned long keylen;
uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen);
if (!item || item[0] <= keylen) return(NULL); // If key not found, or found with no value, return NULL
*valueLen = (uint8_t)(item[0] - (keylen + 1));
return (item + 1 + keylen + 1);
}
uint16_t DNSSD_API TXTRecordGetCount
(
uint16_t txtLen,
const void *txtRecord
)
{
uint16_t count = 0;
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
while (p<e) { p += 1 + p[0]; count++; }
return((p>e) ? (uint16_t)0 : count);
}
(
uint16_t txtLen,
const void *txtRecord
)
{
uint16_t count = 0;
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
while (p<e) { p += 1 + p[0]; count++; }
return((p>e) ? (uint16_t)0 : count);
}
DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
(
uint16_t txtLen,
const void *txtRecord,
uint16_t itemIndex,
uint16_t keyBufLen,
char *key,
uint8_t *valueLen,
const void **value
)
{
uint16_t count = 0;
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
while (p<e && count<itemIndex) { p += 1 + p[0]; count++; } // Find requested item
if (p<e && p + 1 + p[0] <= e) // If valid
{
uint8_t *x = p+1;
unsigned long len = 0;
e = p + 1 + p[0];
while (x+len<e && x[len] != '=') len++;
if (len >= keyBufLen) return(kDNSServiceErr_NoMemory);
memcpy(key, x, len);
key[len] = 0;
if (x+len<e) // If we found '='
{
*value = x + len + 1;
*valueLen = (uint8_t)(p[0] - (len + 1));
}
else
{
*value = NULL;
*valueLen = 0;
}
return(kDNSServiceErr_NoError);
}
return(kDNSServiceErr_Invalid);
}
(
uint16_t txtLen,
const void *txtRecord,
uint16_t itemIndex,
uint16_t keyBufLen,
char *key,
uint8_t *valueLen,
const void **value
)
{
uint16_t count = 0;
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
while (p<e && count<itemIndex) { p += 1 + p[0]; count++; } // Find requested item
if (p<e && p + 1 + p[0] <= e) // If valid
{
uint8_t *x = p+1;
unsigned long len = 0;
e = p + 1 + p[0];
while (x+len<e && x[len] != '=') len++;
if (len >= keyBufLen) return(kDNSServiceErr_NoMemory);
memcpy(key, x, len);
key[len] = 0;
if (x+len<e) // If we found '='
{
*value = x + len + 1;
*valueLen = (uint8_t)(p[0] - (len + 1));
}
else
{
*value = NULL;
*valueLen = 0;
}
return(kDNSServiceErr_NoError);
}
return(kDNSServiceErr_Invalid);
}
/*********************************************************************************************
*
* SCCS-compatible version string
*
*********************************************************************************************/
*
* SCCS-compatible version string
*
*********************************************************************************************/
// For convenience when using the "strings" command, this is the last thing in the file
// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
// To expand "version" to its value before making the string, use STRINGIFY(version) instead
#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
// NOT static -- otherwise the compiler may optimize it out
// The "@(#) " pattern is a special prefix the "what" command looks for
const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion);
const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";

File diff suppressed because it is too large Load Diff

View File

@ -31,131 +31,131 @@
#if defined(_WIN32)
char *win32_strerror(int inErrorCode)
{
static char buffer[1024];
DWORD n;
memset(buffer, 0, sizeof(buffer));
n = FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
(DWORD) inErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buffer,
sizeof(buffer),
NULL);
if (n > 0)
{
// Remove any trailing CR's or LF's since some messages have them.
while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1]))
buffer[--n] = '\0';
}
return buffer;
}
{
static char buffer[1024];
DWORD n;
memset(buffer, 0, sizeof(buffer));
n = FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
(DWORD) inErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buffer,
sizeof(buffer),
NULL);
if (n > 0)
{
// Remove any trailing CR's or LF's since some messages have them.
while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1]))
buffer[--n] = '\0';
}
return buffer;
}
#endif
void put_uint32(const uint32_t l, char **ptr)
{
(*ptr)[0] = (char)((l >> 24) & 0xFF);
(*ptr)[1] = (char)((l >> 16) & 0xFF);
(*ptr)[2] = (char)((l >> 8) & 0xFF);
(*ptr)[3] = (char)((l ) & 0xFF);
*ptr += sizeof(uint32_t);
}
{
(*ptr)[0] = (char)((l >> 24) & 0xFF);
(*ptr)[1] = (char)((l >> 16) & 0xFF);
(*ptr)[2] = (char)((l >> 8) & 0xFF);
(*ptr)[3] = (char)((l ) & 0xFF);
*ptr += sizeof(uint32_t);
}
uint32_t get_uint32(const char **ptr, const char *end)
{
if (!*ptr || *ptr + sizeof(uint32_t) > end)
{
*ptr = NULL;
return(0);
}
else
{
uint8_t *p = (uint8_t*) *ptr;
*ptr += sizeof(uint32_t);
return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
}
}
{
if (!*ptr || *ptr + sizeof(uint32_t) > end)
{
*ptr = NULL;
return(0);
}
else
{
uint8_t *p = (uint8_t*) *ptr;
*ptr += sizeof(uint32_t);
return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
}
}
void put_uint16(uint16_t s, char **ptr)
{
(*ptr)[0] = (char)((s >> 8) & 0xFF);
(*ptr)[1] = (char)((s ) & 0xFF);
*ptr += sizeof(uint16_t);
}
{
(*ptr)[0] = (char)((s >> 8) & 0xFF);
(*ptr)[1] = (char)((s ) & 0xFF);
*ptr += sizeof(uint16_t);
}
uint16_t get_uint16(const char **ptr, const char *end)
{
if (!*ptr || *ptr + sizeof(uint16_t) > end)
{
*ptr = NULL;
return(0);
}
else
{
uint8_t *p = (uint8_t*) *ptr;
*ptr += sizeof(uint16_t);
return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
}
}
{
if (!*ptr || *ptr + sizeof(uint16_t) > end)
{
*ptr = NULL;
return(0);
}
else
{
uint8_t *p = (uint8_t*) *ptr;
*ptr += sizeof(uint16_t);
return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
}
}
int put_string(const char *str, char **ptr)
{
if (!str) str = "";
strcpy(*ptr, str);
*ptr += strlen(str) + 1;
return 0;
}
{
if (!str) str = "";
strcpy(*ptr, str);
*ptr += strlen(str) + 1;
return 0;
}
int get_string(const char **ptr, const char *const end, char *buffer, int buflen)
{
if (!*ptr)
{
*buffer = 0;
return(-1);
}
else
{
char *lim = buffer + buflen; // Calculate limit
while (*ptr < end && buffer < lim)
{
char c = *buffer++ = *(*ptr)++;
if (c == 0) return(0); // Success
}
if (buffer == lim) buffer--;
*buffer = 0; // Failed, so terminate string,
*ptr = NULL; // clear pointer,
return(-1); // and return failure indication
}
}
{
if (!*ptr)
{
*buffer = 0;
return(-1);
}
else
{
char *lim = buffer + buflen; // Calculate limit
while (*ptr < end && buffer < lim)
{
char c = *buffer++ = *(*ptr)++;
if (c == 0) return(0); // Success
}
if (buffer == lim) buffer--;
*buffer = 0; // Failed, so terminate string,
*ptr = NULL; // clear pointer,
return(-1); // and return failure indication
}
}
void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr)
{
memcpy(*ptr, rdata, rdlen);
*ptr += rdlen;
}
{
memcpy(*ptr, rdata, rdlen);
*ptr += rdlen;
}
const char *get_rdata(const char **ptr, const char *end, int rdlen)
{
if (!*ptr || *ptr + rdlen > end)
{
*ptr = NULL;
return(0);
}
else
{
const char *rd = *ptr;
*ptr += rdlen;
return rd;
}
}
{
if (!*ptr || *ptr + rdlen > end)
{
*ptr = NULL;
return(0);
}
else
{
const char *rd = *ptr;
*ptr += rdlen;
return rd;
}
}
void ConvertHeaderBytes(ipc_msg_hdr *hdr)
{
hdr->version = htonl(hdr->version);
hdr->datalen = htonl(hdr->datalen);
hdr->ipc_flags = htonl(hdr->ipc_flags);
hdr->op = htonl(hdr->op );
hdr->reg_index = htonl(hdr->reg_index);
}
{
hdr->version = htonl(hdr->version);
hdr->datalen = htonl(hdr->datalen);
hdr->ipc_flags = htonl(hdr->ipc_flags);
hdr->op = htonl(hdr->op );
hdr->reg_index = htonl(hdr->reg_index);
}

View File

@ -35,81 +35,80 @@
// Common cross platform services
//
#if defined(WIN32)
# include <winsock2.h>
# define dnssd_InvalidSocket INVALID_SOCKET
# define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
# define dnssd_EWOULDBLOCK WSAEWOULDBLOCK
# define dnssd_EINTR WSAEINTR
# define dnssd_ECONNRESET WSAECONNRESET
# define dnssd_sock_t SOCKET
# define dnssd_socklen_t int
# define dnssd_close(sock) closesocket(sock)
# define dnssd_errno WSAGetLastError()
# define dnssd_strerror(X) win32_strerror(X)
# define ssize_t int
# define getpid _getpid
# define unlink _unlink
# include <winsock2.h>
# define dnssd_InvalidSocket INVALID_SOCKET
# define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
# define dnssd_EWOULDBLOCK WSAEWOULDBLOCK
# define dnssd_EINTR WSAEINTR
# define dnssd_ECONNRESET WSAECONNRESET
# define dnssd_sock_t SOCKET
# define dnssd_socklen_t int
# define dnssd_close(sock) closesocket(sock)
# define dnssd_errno WSAGetLastError()
# define dnssd_strerror(X) win32_strerror(X)
# define ssize_t int
# define getpid _getpid
# define unlink _unlink
extern char *win32_strerror(int inErrorCode);
#else
# include <sys/types.h>
# include <unistd.h>
# include <sys/un.h>
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/stat.h>
# include <sys/socket.h>
# include <netinet/in.h>
# define dnssd_InvalidSocket -1
# define dnssd_SocketValid(s) ((s) >= 0)
# define dnssd_EWOULDBLOCK EWOULDBLOCK
# define dnssd_EINTR EINTR
# define dnssd_ECONNRESET ECONNRESET
# define dnssd_EPIPE EPIPE
# define dnssd_sock_t int
# define dnssd_socklen_t unsigned int
# define dnssd_close(sock) close(sock)
# define dnssd_errno errno
# define dnssd_strerror(X) strerror(X)
# include <sys/types.h>
# include <unistd.h>
# include <sys/un.h>
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/stat.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# define dnssd_InvalidSocket -1
# define dnssd_SocketValid(s) ((s) >= 0)
# define dnssd_EWOULDBLOCK EWOULDBLOCK
# define dnssd_EINTR EINTR
# define dnssd_ECONNRESET ECONNRESET
# define dnssd_EPIPE EPIPE
# define dnssd_sock_t int
# define dnssd_socklen_t unsigned int
# define dnssd_close(sock) close(sock)
# define dnssd_errno errno
# define dnssd_strerror(X) strerror(X)
#endif
#if defined(USE_TCP_LOOPBACK)
# define AF_DNSSD AF_INET
# define MDNS_TCP_SERVERADDR "127.0.0.1"
# define MDNS_TCP_SERVERPORT 5354
# define LISTENQ 5
# define dnssd_sockaddr_t struct sockaddr_in
# define AF_DNSSD AF_INET
# define MDNS_TCP_SERVERADDR "127.0.0.1"
# define MDNS_TCP_SERVERPORT 5354
# define LISTENQ 5
# define dnssd_sockaddr_t struct sockaddr_in
#else
# define AF_DNSSD AF_LOCAL
# ifndef MDNS_UDS_SERVERPATH
# define MDNS_UDS_SERVERPATH "/var/run/mDNSResponder"
# endif
# define LISTENQ 100
// longest legal control path length
# define MAX_CTLPATH 256
# define dnssd_sockaddr_t struct sockaddr_un
# define AF_DNSSD AF_LOCAL
# ifndef MDNS_UDS_SERVERPATH
# define MDNS_UDS_SERVERPATH "/var/run/mDNSResponder"
# endif
# define MDNS_UDS_SERVERPATH_ENVVAR "DNSSD_UDS_PATH"
# define LISTENQ 100
// longest legal control path length
# define MAX_CTLPATH 256
# define dnssd_sockaddr_t struct sockaddr_un
#endif
// Compatibility workaround
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#define AF_LOCAL AF_UNIX
#endif
// General UDS constants
#define TXT_RECORD_INDEX ((uint32_t)(-1)) // record index for default text record
#define TXT_RECORD_INDEX ((uint32_t)(-1)) // record index for default text record
// IPC data encoding constants and types
#define VERSION 1
#define IPC_FLAGS_NOREPLY 1 // set flag if no asynchronous replies are to be sent to client
#define IPC_FLAGS_NOREPLY 1 // set flag if no asynchronous replies are to be sent to client
// Structure packing macro. If we're not using GNUC, it's not fatal. Most compilers naturally pack the on-the-wire
// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
// correctly, our compile-time assertion checks will catch it and prevent inadvertent generation of non-working code.
#ifndef packedstruct
#ifdef __packed
#define packedstruct struct __packed
#define packedunion union __packed
#elif ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
#if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
#define packedstruct struct __attribute__((__packed__))
#define packedunion union __attribute__((__packed__))
#else
@ -119,10 +118,10 @@ extern char *win32_strerror(int inErrorCode);
#endif
typedef enum
{
request_op_none = 0, // No request yet received on this connection
connection_request = 1, // connected socket via DNSServiceConnect()
reg_record_request, // reg/remove record only valid for connected sockets
{
request_op_none = 0, // No request yet received on this connection
connection_request = 1, // connected socket via DNSServiceConnect()
reg_record_request, // reg/remove record only valid for connected sockets
remove_record_request,
enumeration_request,
reg_service_request,
@ -132,52 +131,59 @@ typedef enum
reconfirm_record_request,
add_record_request,
update_record_request,
setdomain_request, // Up to here is in Tiger and B4W 1.0.3
getproperty_request, // New in B4W 1.0.4
port_mapping_request, // New in Leopard and B4W 2.0
addrinfo_request,
send_bpf, // New in SL
setdomain_request, // Up to here is in Tiger and B4W 1.0.3
getproperty_request, // New in B4W 1.0.4
port_mapping_request, // New in Leopard and B4W 2.0
addrinfo_request,
send_bpf, // New in SL
getpid_request,
release_request,
connection_delegate_request,
cancel_request = 63
} request_op_t;
cancel_request = 63
} request_op_t;
typedef enum
{
{
enumeration_reply_op = 64,
reg_service_reply_op,
browse_reply_op,
resolve_reply_op,
query_reply_op,
reg_record_reply_op, // Up to here is in Tiger and B4W 1.0.3
getproperty_reply_op, // New in B4W 1.0.4
port_mapping_reply_op, // New in Leopard and B4W 2.0
addrinfo_reply_op
} reply_op_t;
reg_record_reply_op, // Up to here is in Tiger and B4W 1.0.3
getproperty_reply_op, // New in B4W 1.0.4
port_mapping_reply_op, // New in Leopard and B4W 2.0
addrinfo_reply_op
} reply_op_t;
#if defined(_WIN64)
# pragma pack(4)
# pragma pack(push,4)
#endif
// Define context object big enough to hold a 64-bit pointer,
// to accomodate 64-bit clients communicating with 32-bit daemon.
// There's no reason for the daemon to ever be a 64-bit process, but its clients might be
typedef packedunion
{
{
void *context;
uint32_t u32[2];
} client_context_t;
} client_context_t;
typedef packedstruct
{
{
uint32_t version;
uint32_t datalen;
uint32_t ipc_flags;
uint32_t op; // request_op_t or reply_op_t
uint32_t op; // request_op_t or reply_op_t
client_context_t client_context; // context passed from client, returned by server in corresponding reply
uint32_t reg_index; // identifier for a record registered via DNSServiceRegisterRecord() on a
// socket connected by DNSServiceCreateConnection(). Must be unique in the scope of the connection, such that and
// index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord())
} ipc_msg_hdr;
} ipc_msg_hdr;
#if defined(_WIN64)
# pragma pack(pop)
#endif
// routines to write to and extract data from message buffers.
// caller responsible for bounds checking.
@ -201,16 +207,16 @@ int get_string(const char **ptr, const char *const end, char *buffer, int buflen
void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
const char *get_rdata(const char **ptr, const char *end, int rdlen); // return value is rdata pointed to by *ptr -
// rdata is not copied from buffer.
// rdata is not copied from buffer.
void ConvertHeaderBytes(ipc_msg_hdr *hdr);
struct CompileTimeAssertionChecks_dnssd_ipc
{
// Check that the compiler generated our on-the-wire packet format structure definitions
// properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
char assert0[(sizeof(client_context_t) == 8) ? 1 : -1];
char assert1[(sizeof(ipc_msg_hdr) == 28) ? 1 : -1];
};
{
// Check that the compiler generated our on-the-wire packet format structure definitions
// properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
char assert0[(sizeof(client_context_t) == 8) ? 1 : -1];
char assert1[(sizeof(ipc_msg_hdr) == 28) ? 1 : -1];
};
#endif // DNSSD_IPC_H

View File

@ -5,20 +5,20 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
File: mDNSDebug.c
File: mDNSDebug.c
Contains: Implementation of debugging utilities. Requires a POSIX environment.
Contains: Implementation of debugging utilities. Requires a POSIX environment.
Version: 1.0
Version: 1.0
*/
@ -37,8 +37,10 @@
#include "mDNSEmbeddedAPI.h"
mDNSexport int mDNS_LoggingEnabled = 0;
mDNSexport int mDNS_LoggingEnabled = 0;
mDNSexport int mDNS_PacketLoggingEnabled = 0;
mDNSexport int mDNS_McastLoggingEnabled = 0;
mDNSexport int mDNS_McastTracingEnabled = 0;
#if MDNS_DEBUGMSGS
mDNSexport int mDNS_DebugMode = mDNStrue;
@ -50,31 +52,31 @@ mDNSexport int mDNS_DebugMode = mDNSfalse;
// how to print special data types like IP addresses and length-prefixed domain names
#if MDNS_DEBUGMSGS > 1
mDNSexport void verbosedebugf_(const char *format, ...)
{
char buffer[512];
va_list ptr;
va_start(ptr,format);
buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0;
va_end(ptr);
mDNSPlatformWriteDebugMsg(buffer);
}
{
char buffer[512];
va_list ptr;
va_start(ptr,format);
buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0;
va_end(ptr);
mDNSPlatformWriteDebugMsg(buffer);
}
#endif
// Log message with default "mDNSResponder" ident string at the start
mDNSlocal void LogMsgWithLevelv(mDNSLogLevel_t logLevel, const char *format, va_list ptr)
{
char buffer[512];
buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
mDNSPlatformWriteLogMsg(ProgramName, buffer, logLevel);
}
{
char buffer[512];
buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
mDNSPlatformWriteLogMsg(ProgramName, buffer, logLevel);
}
#define LOG_HELPER_BODY(L) \
{ \
va_list ptr; \
va_start(ptr,format); \
LogMsgWithLevelv(L, format, ptr); \
va_end(ptr); \
}
{ \
va_list ptr; \
va_start(ptr,format); \
LogMsgWithLevelv(L, format, ptr); \
va_end(ptr); \
}
// see mDNSDebug.h
#if !MDNS_HAS_VA_ARG_MACROS
@ -90,4 +92,4 @@ void debugf_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_DEBUG)
// Log message with default "mDNSResponder" ident string at the start
mDNSexport void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...)
LOG_HELPER_BODY(logLevel)
LOG_HELPER_BODY(logLevel)

View File

@ -50,7 +50,7 @@ has no user-specifiable command-line argument, and users should not run
.Nm
manually.
.Pp
.Ss LOGGING
.Sh LOGGING
There are several methods with which to examine
.Nm Ns 's internal state for debugging and diagnostic purposes. The syslog(1)
logging levels map as follows:
@ -83,8 +83,8 @@ A SIGINFO signal will dump a snapshot summary of the internal state to
.Sh FILES
.Pa /usr/sbin/mDNSResponder \" Pathname
.\"
.Sh SEE ALSO
.Xr mDNS 1
.Pp
.Sh INFO
.Pp
For information on Multicast DNS, see
.Pa http://www.multicastdns.org/

File diff suppressed because it is too large Load Diff

View File

@ -5,20 +5,20 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
File: uds_daemon.h
File: uds_daemon.h
Contains: Interfaces necessary to talk to uds_daemon.c.
Contains: Interfaces necessary to talk to uds_daemon.c.
Version: 1.0
Version: 1.0
*/
@ -31,13 +31,18 @@
extern int udsserver_init(dnssd_sock_t skts[], mDNSu32 count);
extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
extern void udsserver_info(mDNS *const m); // print out info about current state
extern void udsserver_info(mDNS *const m); // print out info about current state
extern void udsserver_handle_configchange(mDNS *const m);
extern int udsserver_exit(void); // should be called prior to app exit
extern int udsserver_exit(void); // should be called prior to app exit
extern void LogMcastStateInfo(mDNS *const m, mDNSBool mflag, mDNSBool start, mDNSBool mstatelog);
#define LogMcastQ (mDNS_McastLoggingEnabled == 0) ? ((void)0) : LogMcastQuestion
#define LogMcastS (mDNS_McastLoggingEnabled == 0) ? ((void)0) : LogMcastService
#define LogMcast (mDNS_McastLoggingEnabled == 0) ? ((void)0) : LogMsg
#define LogMcastNoIdent (mDNS_McastLoggingEnabled == 0) ? ((void)0) : LogMsgNoIdent
/* Routines that uds_daemon expects to link against: */
typedef void (*udsEventCallback)(int fd, short filter, void *context);
typedef void (*udsEventCallback)(int fd, short filter, void *context);
extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context, void **platform_data);
extern int udsSupportReadFD(dnssd_sock_t fd, char* buf, int len, int flags, void *platform_data);
extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd, void *platform_data); // Note: This also CLOSES the file descriptor as well
@ -50,30 +55,35 @@ extern mDNS mDNSStorage;
extern DNameListElem *AutoRegistrationDomains;
extern DNameListElem *AutoBrowseDomains;
extern mDNSs32 ChopSubTypes(char *regtype);
extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p);
extern mDNSs32 ChopSubTypes(char *regtype, char **AnonData);
extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData);
extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port);
extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result);
extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs);
#if APPLE_OSX_mDNSResponder
extern void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add);
extern void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add);
// External support
extern void mDNSInitPacketFilter(void);
extern void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype);
extern void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype);
extern void external_start_advertising_service(const ResourceRecord *const resourceRecord);
extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord);
extern void external_start_resolving_service(const domainname *const fqdn);
extern void external_stop_resolving_service(const domainname *const fqdn);
#else
#define external_start_browsing_for_service(A,B,C) (void)(A)
#define external_stop_browsing_for_service(A,B,C) (void)(A)
#define external_start_advertising_service(A) (void)(A)
#define external_stop_advertising_service(A) (void)(A)
#define external_start_resolving_service(A) (void)(A)
#define external_stop_resolving_service(A) (void)(A)
// D2D interface support
extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
extern void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
extern void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
extern void external_connection_release(const domainname *instance);
#else // APPLE_OSX_mDNSResponder
#define external_start_browsing_for_service(A,B,C,D) (void)(A)
#define external_stop_browsing_for_service(A,B,C,D) (void)(A)
#define external_start_advertising_service(A,B) (void)(A)
#define external_stop_advertising_service(A,B) (void)(A)
#define external_start_resolving_service(A,B,C) (void)(A)
#define external_stop_resolving_service(A,B,C) (void)(A)
#define external_connection_release(A) (void)(A)
#endif // APPLE_OSX_mDNSResponder
extern const char mDNSResponderVersionString_SCCS[];