⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dnskey.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Find public key in DNS * Copyright (C) 2000-2002  D. Hugh Redelmeier. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * for more details. * * RCSID $Id: dnskey.c,v 1.84 2004/11/30 16:34:08 mcr Exp $ */#include <stdlib.h>#include <stddef.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/nameser.h>#include <resolv.h>#include <netdb.h>	/* ??? for h_errno */#include <sys/queue.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "adns.h"	/* needs <resolv.h> */#include "defs.h"#include "id.h"#include "log.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h"	/* needs id.h */#include "keys.h"	    /* needs connections.h */#include "dnskey.h"#include "packet.h"#include "timer.h"#include "server.h"/* somebody has to decide */#define MAX_TXT_RDATA	((MAX_KEY_BYTES * 8 / 6) + 40)	/* somewhat arbitrary overkill *//* ADNS stuff */int adns_qfd = NULL_FD,	/* file descriptor for sending queries to adns (O_NONBLOCK) */    adns_afd = NULL_FD;	/* file descriptor for receiving answers from adns */static pid_t adns_pid = 0;const char *pluto_adns_option = NULL;	/* path from --pluto_adns */static int adns_in_flight = 0;	/* queries outstanding */int adns_restart_count;#define ADNS_RESTART_MAX 20static void release_all_continuations(void);bool adns_reapchild(pid_t pid, int status UNUSED){  if(pid == adns_pid) {    close_any(adns_qfd);    adns_qfd = NULL_FD;    close_any(adns_afd);    adns_afd = NULL_FD;    adns_pid = 0;    if(adns_in_flight > 0) {	release_all_continuations();    }    passert(adns_in_flight == 0);    return TRUE;  }  return FALSE;}voidinit_adns(void){    const char *adns_path = pluto_adns_option;    const char *helper_bin_dir = getenv("IPSEC_EXECDIR");#ifndef USE_LWRES    static const char adns_name[] = "_pluto_adns";#else /* USE_LWRES */    static const char adns_name[] = "lwdnsq";#endif /* USE_LWRES */    char adns_path_space[4096];	/* plenty long? */    int qfds[2];    int afds[2];    /* find a pathname to the ADNS program */    if (adns_path == NULL)    {	/* pathname was not specified as an option: build it.	 * First, figure out the directory to be used.	 */	ssize_t n;	if (helper_bin_dir != NULL)	{	    n = strlen(helper_bin_dir);	    if ((size_t)n <= sizeof(adns_path_space) - sizeof(adns_name))	    {		strcpy(adns_path_space, helper_bin_dir);		if (n > 0 && adns_path_space[n -1] != '/')		    adns_path_space[n++] = '/';	    }	}	else	{	    /* The program will be in the same directory as Pluto,	     * so we use the sympolic link /proc/self/exe to	     * tell us of the path prefix.	     */	    n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space));	    if (n < 0)		exit_log_errno((e		    , "readlink(\"/proc/self/exe\") failed in init_adns()"));	}	if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name))	    exit_log("path to %s is too long", adns_name);	while (n > 0 && adns_path_space[n - 1] != '/')	    n--;	strcpy(adns_path_space + n, adns_name);	adns_path = adns_path_space;    }    if (access(adns_path, X_OK) < 0)	exit_log_errno((e, "%s missing or not executable", adns_path));    if (pipe(qfds) != 0 || pipe(afds) != 0)	exit_log_errno((e, "pipe(2) failed in init_adns()"));    adns_pid = fork();    switch (adns_pid)    {    case -1:	exit_log_errno((e, "fork() failed in init_adns()"));    case 0:	/* child */	{	    /* Make stdin and stdout our pipes.	     * Take care to handle case where pipes already use these fds.	     */	    if (afds[1] == 0)		afds[1] = dup(afds[1]);	/* avoid being overwritten */	    if (qfds[0] != 0)	    {		dup2(qfds[0], 0);		close(qfds[0]);	    }	    if (afds[1] != 1)	    {		dup2(afds[1], 1);		close(qfds[1]);	    }	    if (afds[0] > 1)		close(afds[0]);	    if (afds[1] > 1)		close(afds[1]);	    DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL));	    execlp(adns_path, adns_name, NULL);	    exit_log_errno((e, "execlp of %s failed", adns_path));	}    default:	/* parent */	close(qfds[0]);	adns_qfd = qfds[1];	adns_afd = afds[0];	close(afds[1]);	fcntl(adns_qfd, F_SETFL, O_NONBLOCK);	break;    }}voidstop_adns(void){    close_any(adns_qfd);    adns_qfd = NULL_FD;    close_any(adns_afd);    adns_afd = NULL_FD;    if (adns_pid != 0)    {	int status;	pid_t p = waitpid(adns_pid, &status, 0);	if (p == -1)	{	    log_errno((e, "waitpid for ADNS process failed"));	}	else if (WIFEXITED(status))	{	    if (WEXITSTATUS(status) != 0)		openswan_log("ADNS process exited with status %d"		    , (int) WEXITSTATUS(status));	    adns_pid = 0;	}	else if (WIFSIGNALED(status))	{	    openswan_log("ADNS process terminated by signal %d", (int)WTERMSIG(status));	    adns_pid = 0;	}	else	{	    openswan_log("wait for end of ADNS process returned odd status 0x%x\n"		, status);	    adns_pid = 0;	}    }}/* tricky macro to pass any hot potato */#define TRY(x)	{ err_t ugh = x; if (ugh != NULL) return ugh; }/* Process TXT X-IPsec-Server record, accumulating relevant ones * in cr->gateways_from_dns, a list sorted by "preference". * * Format of TXT record body: X-IPsec-Server ( nnn ) = iii kkk *  nnn is a 16-bit unsigned integer preference *  iii is @FQDN or dotted-decimal IPv4 address or colon-hex IPv6 address *  kkk is an optional RSA public signing key in base 64. * * NOTE: we've got to be very wary of anything we find -- bad guys * might have prepared it. */#define our_TXT_attr_string "X-IPsec-Server"static const char our_TXT_attr[] = our_TXT_attr_string;static err_tdecode_iii(u_char **pp, struct id *gw_id){    u_char *p = *pp + strspn(*pp, " \t");    u_char *e = p + strcspn(p, " \t");    u_char under = *e;    if (p == e)	return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";    *e = '\0';    if (*p == '@')    {	/* gateway specification in this record is @FQDN */	err_t ugh = atoid(p, gw_id, FALSE);	if (ugh != NULL)	    return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s"			     , ugh);    }    else    {	/* gateway specification is numeric */	ip_address ip;	err_t ugh = tnatoaddr(p, e-p	    , strchr(p, ':') == NULL? AF_INET : AF_INET6	    , &ip);	if (ugh != NULL)	    return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s"		, ugh);	if (isanyaddr(&ip))	    return "gateway address must not be 0.0.0.0 or 0::0";	iptoid(&ip, gw_id);    }    *e = under;    *pp = e + strspn(e, " \t");    return NULL;}static err_tprocess_txt_rr_body(u_char *str, bool doit	/* should we capture information? */, enum dns_auth_level dns_auth_level, struct adns_continuation *const cr){    const struct id *client_id = &cr->id;	/* subject of query */    u_char *p = str;    unsigned long pref = 0;    struct gw_info gi;    p += strspn(p, " \t");	/* ignore leading whitespace */    /* is this for us? */    if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0)	return NULL;	/* neither interesting nor bad */    p += sizeof(our_TXT_attr) - 1;	/* ignore our attribute name */    p += strspn(p, " \t");	/* ignore leading whitespace */    /* decode '(' nnn ')' */    if (*p != '(')	return "X-IPsec-Server missing '('";    {	char *e;	p++;	pref = strtoul(p, &e, 0);	if ((u_char *)e == p)	    return "malformed X-IPsec-Server priority";	p = e + strspn(e, " \t");	if (*p != ')')	    return "X-IPsec-Server priority missing ')'";	p++;	p += strspn(p, " \t");	if (pref > 0xFFFF)	    return "X-IPsec-Server priority larger than 0xFFFF";    }    /* time for '=' */    if (*p != '=')	return "X-IPsec-Server priority missing '='";    p++;    p += strspn(p, " \t");    /* Decode iii (Security Gateway ID). */    zero(&gi);	/* before first use */    TRY(decode_iii(&p, &gi.gw_id));	/* will need to unshare_id_content */    if (!cr->sgw_specified)    {	/* we don't know the peer's ID (because we are initiating	 * and we don't know who to initiate with.	 * So we're looking for gateway specs with an IP address	 */	if (!id_is_ipaddr(&gi.gw_id))	{	    DBG(DBG_DNS,		{		    char cidb[IDTOA_BUF];		    char gwidb[IDTOA_BUF];		    idtoa(client_id, cidb, sizeof(cidb));		    idtoa(&gi.gw_id, gwidb, sizeof(gwidb));		    DBG_log("TXT %s record for %s: security gateway %s;"			" ignored because gateway's IP is unspecified"			, our_TXT_attr, cidb, gwidb);		});	    return NULL;	/* we cannot use this record, but it isn't wrong */	}    }    else    {	/* We do know the peer's ID (because we are responding)	 * So we're looking for gateway specs specifying this known ID.	 */	const struct id *peer_id = &cr->sgw_id;	if (!same_id(peer_id, &gi.gw_id))	{	    DBG(DBG_DNS,		{		    char cidb[IDTOA_BUF];		    char gwidb[IDTOA_BUF];		    char pidb[IDTOA_BUF];		    idtoa(client_id, cidb, sizeof(cidb));		    idtoa(&gi.gw_id, gwidb, sizeof(gwidb));		    idtoa(peer_id, pidb, sizeof(pidb));		    DBG_log("TXT %s record for %s: security gateway %s;"			" ignored -- looking to confirm %s as gateway"			, our_TXT_attr, cidb, gwidb, pidb);		});	    return NULL;	/* we cannot use this record, but it isn't wrong */	}    }    if (doit)    {	/* really accept gateway */	struct gw_info **gwip;	/* gateway insertion point */	gi.client_id = *client_id;	/* will need to unshare_id_content */	/* decode optional kkk: base 64 encoding of key */	gi.gw_key_present = *p != '\0';	if (gi.gw_key_present)	{	    /* Decode base 64 encoding of key.	     * Similar code is in process_lwdnsq_key.	     */	    u_char kb[RSA_MAX_ENCODING_BYTES];	/* plenty of space for binary form of public key */	    chunk_t kbc;	    struct RSA_public_key r;	    err_t ugh = ttodatav(p, 0, 64, kb, sizeof(kb), &kbc.len		, diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);	    if (ugh != NULL)		return builddiag("malformed key data: %s", ugh);	    if (kbc.len > sizeof(kb))		return builddiag("key data larger than %lu bytes"		    , (unsigned long) sizeof(kb));	    kbc.ptr = kb;	    ugh = unpack_RSA_public_key(&r, &kbc);	    if (ugh != NULL)		return builddiag("invalid key data: %s", ugh);	    /* now find a key entry to put it in */	    gi.key = public_key_from_rsa(&r);	    free_RSA_public_content(&r);	    unreference_key(&cr->last_info);	    cr->last_info = reference_key(gi.key);	}	/* we're home free!  Allocate everything and add to gateways list. */	gi.refcnt = 1;	gi.pref = pref;	gi.key->dns_auth_level = dns_auth_level;	gi.key->last_tried_time = gi.key->last_worked_time = NO_TIME;	/* find insertion point */	for (gwip = &cr->gateways_from_dns; *gwip != NULL && (*gwip)->pref < pref; gwip = &(*gwip)->next)	    ;	DBG(DBG_DNS,	    {		char cidb[IDTOA_BUF];		char gwidb[IDTOA_BUF];		idtoa(client_id, cidb, sizeof(cidb));		idtoa(&gi.gw_id, gwidb, sizeof(gwidb));		if (gi.gw_key_present)		{		    DBG_log("gateway for %s is %s with key %s"			, cidb, gwidb, gi.key->u.rsa.keyid);		}		else		{		    DBG_log("gateway for %s is %s; no key specified"			, cidb, gwidb);		}	    });	gi.next = *gwip;	*gwip = clone_thing(gi, "gateway info");	unshare_id_content(&(*gwip)->gw_id);	unshare_id_content(&(*gwip)->client_id);    }    return NULL;}static const char *rr_typename(int type){    switch (type)    {    case T_TXT:	return "TXT";    case T_KEY:	return "KEY";    default:	return "???";    }}#ifdef USE_LWRES# ifdef USE_KEYRRstatic err_t

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -