|  | @@ -0,0 +1,185 @@
 | 
		
	
		
			
			|  | 1 | +/*
 | 
		
	
		
			
			|  | 2 | + * Copyright (C) 2012 Patrick Plenefisch <phplenefisch@wpi.edu>.
 | 
		
	
		
			
			|  | 3 | + *
 | 
		
	
		
			
			|  | 4 | + * This program is free software; you can redistribute it and/or
 | 
		
	
		
			
			|  | 5 | + * modify it under the terms of the GNU General Public License as
 | 
		
	
		
			
			|  | 6 | + * published by the Free Software Foundation; either version 2 of the
 | 
		
	
		
			
			|  | 7 | + * License, or any later version.
 | 
		
	
		
			
			|  | 8 | + *
 | 
		
	
		
			
			|  | 9 | + * This program is distributed in the hope that it will be useful, but
 | 
		
	
		
			
			|  | 10 | + * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
		
	
		
			
			|  | 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
		
	
		
			
			|  | 12 | + * General Public License for more details.
 | 
		
	
		
			
			|  | 13 | + *
 | 
		
	
		
			
			|  | 14 | + * You should have received a copy of the GNU General Public License
 | 
		
	
		
			
			|  | 15 | + * along with this program; if not, write to the Free Software
 | 
		
	
		
			
			|  | 16 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
		
	
		
			
			|  | 17 | + * 02110-1301, USA.
 | 
		
	
		
			
			|  | 18 | + */
 | 
		
	
		
			
			|  | 19 | +
 | 
		
	
		
			
			|  | 20 | +FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			|  | 21 | +
 | 
		
	
		
			
			|  | 22 | +#include <stdlib.h>
 | 
		
	
		
			
			|  | 23 | +#include <stdio.h>
 | 
		
	
		
			
			|  | 24 | +#include <string.h>
 | 
		
	
		
			
			|  | 25 | +#include <errno.h>
 | 
		
	
		
			
			|  | 26 | +#include <ipxe/resolv.h>
 | 
		
	
		
			
			|  | 27 | +#include <ipxe/tcpip.h>
 | 
		
	
		
			
			|  | 28 | +#include <ipxe/monojob.h>
 | 
		
	
		
			
			|  | 29 | +#include <ipxe/settings.h>
 | 
		
	
		
			
			|  | 30 | +#include <usr/nslookup.h>
 | 
		
	
		
			
			|  | 31 | +
 | 
		
	
		
			
			|  | 32 | +/** @file
 | 
		
	
		
			
			|  | 33 | + *
 | 
		
	
		
			
			|  | 34 | + * Standalone name resolution
 | 
		
	
		
			
			|  | 35 | + *
 | 
		
	
		
			
			|  | 36 | + */
 | 
		
	
		
			
			|  | 37 | +
 | 
		
	
		
			
			|  | 38 | +/** A name resolution request */
 | 
		
	
		
			
			|  | 39 | +struct nslookup {
 | 
		
	
		
			
			|  | 40 | +	/** Reference count for this object */
 | 
		
	
		
			
			|  | 41 | +	struct refcnt refcnt;
 | 
		
	
		
			
			|  | 42 | +
 | 
		
	
		
			
			|  | 43 | +	/** Job control interface */
 | 
		
	
		
			
			|  | 44 | +	struct interface job;
 | 
		
	
		
			
			|  | 45 | +	/** Data transfer interface */
 | 
		
	
		
			
			|  | 46 | +	struct interface resolver;
 | 
		
	
		
			
			|  | 47 | +
 | 
		
	
		
			
			|  | 48 | +	/** Setting name */
 | 
		
	
		
			
			|  | 49 | +	const char *setting_name;
 | 
		
	
		
			
			|  | 50 | +};
 | 
		
	
		
			
			|  | 51 | +
 | 
		
	
		
			
			|  | 52 | +/**
 | 
		
	
		
			
			|  | 53 | + * Terminate name resolution
 | 
		
	
		
			
			|  | 54 | + *
 | 
		
	
		
			
			|  | 55 | + * @v nslookup		Name resolution request
 | 
		
	
		
			
			|  | 56 | + * @v rc		Reason for termination
 | 
		
	
		
			
			|  | 57 | + */
 | 
		
	
		
			
			|  | 58 | +static void nslookup_close ( struct nslookup *nslookup, int rc ) {
 | 
		
	
		
			
			|  | 59 | +
 | 
		
	
		
			
			|  | 60 | +	/* Shut down interfaces */
 | 
		
	
		
			
			|  | 61 | +	intf_shutdown ( &nslookup->resolver, rc );
 | 
		
	
		
			
			|  | 62 | +	intf_shutdown ( &nslookup->job, rc );
 | 
		
	
		
			
			|  | 63 | +}
 | 
		
	
		
			
			|  | 64 | +
 | 
		
	
		
			
			|  | 65 | +/**
 | 
		
	
		
			
			|  | 66 | + * Handle resolved name
 | 
		
	
		
			
			|  | 67 | + *
 | 
		
	
		
			
			|  | 68 | + * @v nslookup		Name resolution request
 | 
		
	
		
			
			|  | 69 | + * @v sa		Completed socket address
 | 
		
	
		
			
			|  | 70 | + */
 | 
		
	
		
			
			|  | 71 | +static void nslookup_resolv_done ( struct nslookup *nslookup,
 | 
		
	
		
			
			|  | 72 | +				   struct sockaddr *sa ) {
 | 
		
	
		
			
			|  | 73 | +	struct sockaddr_in *sin;
 | 
		
	
		
			
			|  | 74 | +	struct setting_type *type;
 | 
		
	
		
			
			|  | 75 | +	void *data;
 | 
		
	
		
			
			|  | 76 | +	size_t len;
 | 
		
	
		
			
			|  | 77 | +	int rc;
 | 
		
	
		
			
			|  | 78 | +
 | 
		
	
		
			
			|  | 79 | +	/* Extract address */
 | 
		
	
		
			
			|  | 80 | +	switch ( sa->sa_family ) {
 | 
		
	
		
			
			|  | 81 | +	case AF_INET:
 | 
		
	
		
			
			|  | 82 | +		sin = ( ( struct sockaddr_in * ) sa );
 | 
		
	
		
			
			|  | 83 | +		data = &sin->sin_addr;
 | 
		
	
		
			
			|  | 84 | +		len = sizeof ( sin->sin_addr );
 | 
		
	
		
			
			|  | 85 | +		type = &setting_type_ipv4;
 | 
		
	
		
			
			|  | 86 | +		break;
 | 
		
	
		
			
			|  | 87 | +	default:
 | 
		
	
		
			
			|  | 88 | +		rc = -ENOTSUP;
 | 
		
	
		
			
			|  | 89 | +		goto err;
 | 
		
	
		
			
			|  | 90 | +	}
 | 
		
	
		
			
			|  | 91 | +
 | 
		
	
		
			
			|  | 92 | +	/* Save in specified setting */
 | 
		
	
		
			
			|  | 93 | +	if ( ( rc = store_named_setting ( nslookup->setting_name, type,
 | 
		
	
		
			
			|  | 94 | +					  data, len ) ) != 0 )
 | 
		
	
		
			
			|  | 95 | +		goto err;
 | 
		
	
		
			
			|  | 96 | +
 | 
		
	
		
			
			|  | 97 | + err:
 | 
		
	
		
			
			|  | 98 | +	/* Terminate name resolution */
 | 
		
	
		
			
			|  | 99 | +	nslookup_close ( nslookup, rc );
 | 
		
	
		
			
			|  | 100 | +}
 | 
		
	
		
			
			|  | 101 | +
 | 
		
	
		
			
			|  | 102 | +/** Name resolution resolver interface operations */
 | 
		
	
		
			
			|  | 103 | +static struct interface_operation nslookup_resolver_operations[] = {
 | 
		
	
		
			
			|  | 104 | +	INTF_OP ( resolv_done, struct nslookup *, nslookup_resolv_done ),
 | 
		
	
		
			
			|  | 105 | +	INTF_OP ( intf_close, struct nslookup *, nslookup_close ),
 | 
		
	
		
			
			|  | 106 | +};
 | 
		
	
		
			
			|  | 107 | +
 | 
		
	
		
			
			|  | 108 | +/** Name resolution resolver interface descriptor */
 | 
		
	
		
			
			|  | 109 | +static struct interface_descriptor nslookup_resolver_desc =
 | 
		
	
		
			
			|  | 110 | +	INTF_DESC_PASSTHRU ( struct nslookup, resolver,
 | 
		
	
		
			
			|  | 111 | +			     nslookup_resolver_operations, job );
 | 
		
	
		
			
			|  | 112 | +
 | 
		
	
		
			
			|  | 113 | +/** Name resolution job control interface operations */
 | 
		
	
		
			
			|  | 114 | +static struct interface_operation nslookup_job_operations[] = {
 | 
		
	
		
			
			|  | 115 | +	INTF_OP ( intf_close, struct nslookup *, nslookup_close ),
 | 
		
	
		
			
			|  | 116 | +};
 | 
		
	
		
			
			|  | 117 | +
 | 
		
	
		
			
			|  | 118 | +/** Name resolution job control interface descriptor */
 | 
		
	
		
			
			|  | 119 | +static struct interface_descriptor nslookup_job_desc =
 | 
		
	
		
			
			|  | 120 | +	INTF_DESC_PASSTHRU ( struct nslookup, job,
 | 
		
	
		
			
			|  | 121 | +			     nslookup_job_operations, resolver );
 | 
		
	
		
			
			|  | 122 | +
 | 
		
	
		
			
			|  | 123 | +/**
 | 
		
	
		
			
			|  | 124 | + * Initiate standalone name resolution
 | 
		
	
		
			
			|  | 125 | + *
 | 
		
	
		
			
			|  | 126 | + * @v job		Parent interface
 | 
		
	
		
			
			|  | 127 | + * @v name		Name to resolve
 | 
		
	
		
			
			|  | 128 | + * @v setting_name	Setting name
 | 
		
	
		
			
			|  | 129 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 130 | + */
 | 
		
	
		
			
			|  | 131 | +static int resolv_setting ( struct interface *job, const char *name,
 | 
		
	
		
			
			|  | 132 | +			    const char *setting_name ) {
 | 
		
	
		
			
			|  | 133 | +	struct nslookup *nslookup;
 | 
		
	
		
			
			|  | 134 | +	struct sockaddr sa;
 | 
		
	
		
			
			|  | 135 | +	char *setting_name_copy;
 | 
		
	
		
			
			|  | 136 | +	int rc;
 | 
		
	
		
			
			|  | 137 | +
 | 
		
	
		
			
			|  | 138 | +	/* Allocate and initialise structure */
 | 
		
	
		
			
			|  | 139 | +	nslookup = zalloc ( sizeof ( *nslookup ) + strlen ( setting_name )
 | 
		
	
		
			
			|  | 140 | +			    + 1 /* NUL */ );
 | 
		
	
		
			
			|  | 141 | +	if ( ! nslookup )
 | 
		
	
		
			
			|  | 142 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 143 | +	ref_init ( &nslookup->refcnt, NULL );
 | 
		
	
		
			
			|  | 144 | +	intf_init ( &nslookup->job, &nslookup_job_desc, &nslookup->refcnt );
 | 
		
	
		
			
			|  | 145 | +	intf_init ( &nslookup->resolver, &nslookup_resolver_desc,
 | 
		
	
		
			
			|  | 146 | +		    &nslookup->refcnt );
 | 
		
	
		
			
			|  | 147 | +	setting_name_copy = ( ( void * ) ( nslookup + 1 ) );
 | 
		
	
		
			
			|  | 148 | +	strcpy ( setting_name_copy, setting_name );
 | 
		
	
		
			
			|  | 149 | +	nslookup->setting_name = setting_name_copy;
 | 
		
	
		
			
			|  | 150 | +
 | 
		
	
		
			
			|  | 151 | +	/* Start name resolution */
 | 
		
	
		
			
			|  | 152 | +	memset ( &sa, 0, sizeof ( sa ) );
 | 
		
	
		
			
			|  | 153 | +	if ( ( rc = resolv ( &nslookup->resolver, name, &sa ) ) != 0 )
 | 
		
	
		
			
			|  | 154 | +		goto err_resolv;
 | 
		
	
		
			
			|  | 155 | +
 | 
		
	
		
			
			|  | 156 | +	/* Attach parent interface, mortalise self, and return */
 | 
		
	
		
			
			|  | 157 | +	intf_plug_plug ( &nslookup->job, job );
 | 
		
	
		
			
			|  | 158 | +	ref_put ( &nslookup->refcnt );
 | 
		
	
		
			
			|  | 159 | +	return 0;
 | 
		
	
		
			
			|  | 160 | +
 | 
		
	
		
			
			|  | 161 | + err_resolv:
 | 
		
	
		
			
			|  | 162 | +	ref_put ( &nslookup->refcnt );
 | 
		
	
		
			
			|  | 163 | +	return rc;
 | 
		
	
		
			
			|  | 164 | +}
 | 
		
	
		
			
			|  | 165 | +
 | 
		
	
		
			
			|  | 166 | +/**
 | 
		
	
		
			
			|  | 167 | + * Perform (blocking) standalone name resolution
 | 
		
	
		
			
			|  | 168 | + *
 | 
		
	
		
			
			|  | 169 | + * @v name		Name to resolve
 | 
		
	
		
			
			|  | 170 | + * @v setting_name	Setting name
 | 
		
	
		
			
			|  | 171 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 172 | + */
 | 
		
	
		
			
			|  | 173 | +int nslookup ( const char *name, const char *setting_name ) {
 | 
		
	
		
			
			|  | 174 | +	int rc;
 | 
		
	
		
			
			|  | 175 | +
 | 
		
	
		
			
			|  | 176 | +	/* Perform name resolution */
 | 
		
	
		
			
			|  | 177 | +	if ( ( rc = resolv_setting ( &monojob, name, setting_name ) ) == 0 )
 | 
		
	
		
			
			|  | 178 | +		rc = monojob_wait ( NULL );
 | 
		
	
		
			
			|  | 179 | +	if ( rc != 0 ) {
 | 
		
	
		
			
			|  | 180 | +		printf ( "Could not resolve %s: %s\n", name, strerror ( rc ) );
 | 
		
	
		
			
			|  | 181 | +		return rc;
 | 
		
	
		
			
			|  | 182 | +	}
 | 
		
	
		
			
			|  | 183 | +
 | 
		
	
		
			
			|  | 184 | +	return 0;
 | 
		
	
		
			
			|  | 185 | +}
 |