import latest mDNSResponder
This commit is contained in:
parent
ee071a7a97
commit
d3be8271c6
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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_
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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[];
|
||||
|
|
Loading…
Reference in New Issue