iPXE
nslookup.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2012 Patrick Plenefisch <phplenefisch@wpi.edu>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  */
00019 
00020 FILE_LICENCE ( GPL2_OR_LATER );
00021 
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <errno.h>
00026 #include <ipxe/resolv.h>
00027 #include <ipxe/tcpip.h>
00028 #include <ipxe/monojob.h>
00029 #include <ipxe/settings.h>
00030 #include <usr/nslookup.h>
00031 
00032 /** @file
00033  *
00034  * Standalone name resolution
00035  *
00036  */
00037 
00038 /** A name resolution request */
00039 struct nslookup {
00040         /** Reference count for this object */
00041         struct refcnt refcnt;
00042 
00043         /** Job control interface */
00044         struct interface job;
00045         /** Data transfer interface */
00046         struct interface resolver;
00047 
00048         /** Setting name */
00049         char *setting_name;
00050 };
00051 
00052 /**
00053  * Terminate name resolution
00054  *
00055  * @v nslookup          Name resolution request
00056  * @v rc                Reason for termination
00057  */
00058 static void nslookup_close ( struct nslookup *nslookup, int rc ) {
00059 
00060         /* Shut down interfaces */
00061         intf_shutdown ( &nslookup->resolver, rc );
00062         intf_shutdown ( &nslookup->job, rc );
00063 }
00064 
00065 /**
00066  * Handle resolved name
00067  *
00068  * @v nslookup          Name resolution request
00069  * @v sa                Completed socket address
00070  */
00071 static void nslookup_resolv_done ( struct nslookup *nslookup,
00072                                    struct sockaddr *sa ) {
00073         struct sockaddr_in *sin;
00074         struct sockaddr_in6 *sin6;
00075         const struct setting_type *default_type;
00076         struct settings *settings;
00077         struct setting setting;
00078         void *data;
00079         size_t len;
00080         int rc;
00081 
00082         /* Extract address */
00083         switch ( sa->sa_family ) {
00084         case AF_INET:
00085                 sin = ( ( struct sockaddr_in * ) sa );
00086                 data = &sin->sin_addr;
00087                 len = sizeof ( sin->sin_addr );
00088                 default_type = &setting_type_ipv4;
00089                 break;
00090         case AF_INET6:
00091                 sin6 = ( ( struct sockaddr_in6 * ) sa );
00092                 data = &sin6->sin6_addr;
00093                 len = sizeof ( sin6->sin6_addr );
00094                 default_type = &setting_type_ipv6;
00095                 break;
00096         default:
00097                 rc = -ENOTSUP;
00098                 goto err;
00099         }
00100 
00101         /* Parse specified setting name */
00102         if ( ( rc = parse_setting_name ( nslookup->setting_name,
00103                                          autovivify_child_settings, &settings,
00104                                          &setting ) ) != 0 )
00105                 goto err;
00106 
00107         /* Apply default type if necessary */
00108         if ( ! setting.type )
00109                 setting.type = default_type;
00110 
00111         /* Store in specified setting */
00112         if ( ( rc = store_setting ( settings, &setting, data, len ) ) != 0 )
00113                 goto err;
00114 
00115  err:
00116         /* Terminate name resolution */
00117         nslookup_close ( nslookup, rc );
00118 }
00119 
00120 /** Name resolution resolver interface operations */
00121 static struct interface_operation nslookup_resolver_operations[] = {
00122         INTF_OP ( resolv_done, struct nslookup *, nslookup_resolv_done ),
00123         INTF_OP ( intf_close, struct nslookup *, nslookup_close ),
00124 };
00125 
00126 /** Name resolution resolver interface descriptor */
00127 static struct interface_descriptor nslookup_resolver_desc =
00128         INTF_DESC_PASSTHRU ( struct nslookup, resolver,
00129                              nslookup_resolver_operations, job );
00130 
00131 /** Name resolution job control interface operations */
00132 static struct interface_operation nslookup_job_operations[] = {
00133         INTF_OP ( intf_close, struct nslookup *, nslookup_close ),
00134 };
00135 
00136 /** Name resolution job control interface descriptor */
00137 static struct interface_descriptor nslookup_job_desc =
00138         INTF_DESC_PASSTHRU ( struct nslookup, job,
00139                              nslookup_job_operations, resolver );
00140 
00141 /**
00142  * Initiate standalone name resolution
00143  *
00144  * @v job               Parent interface
00145  * @v name              Name to resolve
00146  * @v setting_name      Setting name
00147  * @ret rc              Return status code
00148  */
00149 static int resolv_setting ( struct interface *job, const char *name,
00150                             const char *setting_name ) {
00151         struct nslookup *nslookup;
00152         struct sockaddr sa;
00153         char *setting_name_copy;
00154         int rc;
00155 
00156         /* Allocate and initialise structure */
00157         nslookup = zalloc ( sizeof ( *nslookup ) + strlen ( setting_name )
00158                             + 1 /* NUL */ );
00159         if ( ! nslookup )
00160                 return -ENOMEM;
00161         ref_init ( &nslookup->refcnt, NULL );
00162         intf_init ( &nslookup->job, &nslookup_job_desc, &nslookup->refcnt );
00163         intf_init ( &nslookup->resolver, &nslookup_resolver_desc,
00164                     &nslookup->refcnt );
00165         setting_name_copy = ( ( void * ) ( nslookup + 1 ) );
00166         strcpy ( setting_name_copy, setting_name );
00167         nslookup->setting_name = setting_name_copy;
00168 
00169         /* Start name resolution */
00170         memset ( &sa, 0, sizeof ( sa ) );
00171         if ( ( rc = resolv ( &nslookup->resolver, name, &sa ) ) != 0 )
00172                 goto err_resolv;
00173 
00174         /* Attach parent interface, mortalise self, and return */
00175         intf_plug_plug ( &nslookup->job, job );
00176         ref_put ( &nslookup->refcnt );
00177         return 0;
00178 
00179  err_resolv:
00180         ref_put ( &nslookup->refcnt );
00181         return rc;
00182 }
00183 
00184 /**
00185  * Perform (blocking) standalone name resolution
00186  *
00187  * @v name              Name to resolve
00188  * @v setting_name      Setting name
00189  * @ret rc              Return status code
00190  */
00191 int nslookup ( const char *name, const char *setting_name ) {
00192         int rc;
00193 
00194         /* Perform name resolution */
00195         if ( ( rc = resolv_setting ( &monojob, name, setting_name ) ) == 0 )
00196                 rc = monojob_wait ( NULL, 0 );
00197         if ( rc != 0 ) {
00198                 printf ( "Could not resolve %s: %s\n", name, strerror ( rc ) );
00199                 return rc;
00200         }
00201 
00202         return 0;
00203 }