iPXE
resolv.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
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  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdint.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <errno.h>
00030 #include <ipxe/xfer.h>
00031 #include <ipxe/open.h>
00032 #include <ipxe/process.h>
00033 #include <ipxe/socket.h>
00034 #include <ipxe/resolv.h>
00035 
00036 /** @file
00037  *
00038  * Name resolution
00039  *
00040  */
00041 
00042 /***************************************************************************
00043  *
00044  * Name resolution interfaces
00045  *
00046  ***************************************************************************
00047  */
00048 
00049 /**
00050  * Name resolved
00051  *
00052  * @v intf              Object interface
00053  * @v sa                Completed socket address (if successful)
00054  */
00055 void resolv_done ( struct interface *intf, struct sockaddr *sa ) {
00056         struct interface *dest;
00057         resolv_done_TYPE ( void * ) *op =
00058                 intf_get_dest_op ( intf, resolv_done, &dest );
00059         void *object = intf_object ( dest );
00060 
00061         DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " resolv_done\n",
00062                INTF_INTF_DBG ( intf, dest ) );
00063 
00064         if ( op ) {
00065                 op ( object, sa );
00066         } else {
00067                 /* Default is to ignore resolutions */
00068         }
00069 
00070         intf_put ( dest );
00071 }
00072 
00073 /***************************************************************************
00074  *
00075  * Numeric name resolver
00076  *
00077  ***************************************************************************
00078  */
00079 
00080 /** A numeric name resolver */
00081 struct numeric_resolv {
00082         /** Reference counter */
00083         struct refcnt refcnt;
00084         /** Name resolution interface */
00085         struct interface resolv;
00086         /** Process */
00087         struct process process;
00088         /** Completed socket address */
00089         struct sockaddr sa;
00090         /** Overall status code */
00091         int rc;
00092 };
00093 
00094 static void numeric_step ( struct numeric_resolv *numeric ) {
00095 
00096         if ( numeric->rc == 0 )
00097                 resolv_done ( &numeric->resolv, &numeric->sa );
00098         intf_shutdown ( &numeric->resolv, numeric->rc );
00099 }
00100 
00101 static struct process_descriptor numeric_process_desc =
00102         PROC_DESC_ONCE ( struct numeric_resolv, process, numeric_step );
00103 
00104 static int numeric_resolv ( struct interface *resolv,
00105                             const char *name, struct sockaddr *sa ) {
00106         struct numeric_resolv *numeric;
00107 
00108         /* Allocate and initialise structure */
00109         numeric = zalloc ( sizeof ( *numeric ) );
00110         if ( ! numeric )
00111                 return -ENOMEM;
00112         ref_init ( &numeric->refcnt, NULL );
00113         intf_init ( &numeric->resolv, &null_intf_desc, &numeric->refcnt );
00114         process_init ( &numeric->process, &numeric_process_desc,
00115                        &numeric->refcnt );
00116         memcpy ( &numeric->sa, sa, sizeof ( numeric->sa ) );
00117 
00118         /* Attempt to resolve name */
00119         numeric->rc = sock_aton ( name, &numeric->sa );
00120 
00121         /* Attach to parent interface, mortalise self, and return */
00122         intf_plug_plug ( &numeric->resolv, resolv );
00123         ref_put ( &numeric->refcnt );
00124         return 0;
00125 }
00126 
00127 struct resolver numeric_resolver __resolver ( RESOLV_NUMERIC ) = {
00128         .name = "NUMERIC",
00129         .resolv = numeric_resolv,
00130 };
00131 
00132 /***************************************************************************
00133  *
00134  * Name resolution multiplexer
00135  *
00136  ***************************************************************************
00137  */
00138 
00139 /** A name resolution multiplexer */
00140 struct resolv_mux {
00141         /** Reference counter */
00142         struct refcnt refcnt;
00143         /** Parent name resolution interface */
00144         struct interface parent;
00145 
00146         /** Child name resolution interface */
00147         struct interface child;
00148         /** Current child resolver */
00149         struct resolver *resolver;
00150 
00151         /** Socket address to complete */
00152         struct sockaddr sa;
00153         /** Name to be resolved
00154          *
00155          * Must be at end of structure
00156          */
00157         char name[0];
00158 };
00159 
00160 /**
00161  * Try current child name resolver
00162  *
00163  * @v mux               Name resolution multiplexer
00164  * @ret rc              Return status code
00165  */
00166 static int resmux_try ( struct resolv_mux *mux ) {
00167         struct resolver *resolver = mux->resolver;
00168         int rc;
00169 
00170         DBGC ( mux, "RESOLV %p trying method %s\n", mux, resolver->name );
00171 
00172         if ( ( rc = resolver->resolv ( &mux->child, mux->name,
00173                                        &mux->sa ) ) != 0 ) {
00174                 DBGC ( mux, "RESOLV %p could not use method %s: %s\n",
00175                        mux, resolver->name, strerror ( rc ) );
00176                 return rc;
00177         }
00178 
00179         return 0;
00180 }
00181 
00182 /**
00183  * Close name resolution multiplexer
00184  *
00185  * @v mux               Name resolution multiplexer
00186  * @v rc                Reason for close
00187  */
00188 static void resmux_close ( struct resolv_mux *mux, int rc ) {
00189 
00190         /* Shut down all interfaces */
00191         intf_shutdown ( &mux->child, rc );
00192         intf_shutdown ( &mux->parent, rc );
00193 }
00194 
00195 /**
00196  * Child finished resolution
00197  *
00198  * @v mux               Name resolution multiplexer
00199  * @v rc                Return status code
00200  */
00201 static void resmux_child_close ( struct resolv_mux *mux, int rc ) {
00202 
00203         /* Restart child interface */
00204         intf_restart ( &mux->child, rc );
00205 
00206         /* If this resolution succeeded, stop now */
00207         if ( rc == 0 ) {
00208                 DBGC ( mux, "RESOLV %p succeeded using method %s\n",
00209                        mux, mux->resolver->name );
00210                 goto finished;
00211         }
00212 
00213         /* Attempt next child resolver, if possible */
00214         mux->resolver++;
00215         if ( mux->resolver >= table_end ( RESOLVERS ) ) {
00216                 DBGC ( mux, "RESOLV %p failed to resolve name\n", mux );
00217                 goto finished;
00218         }
00219         if ( ( rc = resmux_try ( mux ) ) != 0 )
00220                 goto finished;
00221 
00222         /* Next resolver is now running */
00223         return;
00224 
00225  finished:
00226         resmux_close ( mux, rc );
00227 }
00228 
00229 /** Name resolution multiplexer child interface operations */
00230 static struct interface_operation resmux_child_op[] = {
00231         INTF_OP ( intf_close, struct resolv_mux *, resmux_child_close ),
00232 };
00233 
00234 /** Name resolution multiplexer child interface descriptor */
00235 static struct interface_descriptor resmux_child_desc =
00236         INTF_DESC_PASSTHRU ( struct resolv_mux, child, resmux_child_op,
00237                              parent );
00238 
00239 /** Name resolution multiplexer parent interface operations */
00240 static struct interface_operation resmux_parent_op[] = {
00241         INTF_OP ( intf_close, struct resolv_mux *, resmux_close ),
00242 };
00243 
00244 /** Name resolution multiplexer parent interface descriptor */
00245 static struct interface_descriptor resmux_parent_desc =
00246         INTF_DESC_PASSTHRU ( struct resolv_mux, parent, resmux_parent_op,
00247                              child );
00248 
00249 /**
00250  * Start name resolution
00251  *
00252  * @v resolv            Name resolution interface
00253  * @v name              Name to resolve
00254  * @v sa                Socket address to complete
00255  * @ret rc              Return status code
00256  */
00257 int resolv ( struct interface *resolv, const char *name,
00258              struct sockaddr *sa ) {
00259         struct resolv_mux *mux;
00260         size_t name_len = ( strlen ( name ) + 1 );
00261         int rc;
00262 
00263         /* Allocate and initialise structure */
00264         mux = zalloc ( sizeof ( *mux ) + name_len );
00265         if ( ! mux )
00266                 return -ENOMEM;
00267         ref_init ( &mux->refcnt, NULL );
00268         intf_init ( &mux->parent, &resmux_parent_desc, &mux->refcnt );
00269         intf_init ( &mux->child, &resmux_child_desc, &mux->refcnt );
00270         mux->resolver = table_start ( RESOLVERS );
00271         if ( sa )
00272                 memcpy ( &mux->sa, sa, sizeof ( mux->sa ) );
00273         memcpy ( mux->name, name, name_len );
00274 
00275         DBGC ( mux, "RESOLV %p attempting to resolve \"%s\"\n", mux, name );
00276 
00277         /* Start first resolver in chain.  There will always be at
00278          * least one resolver (the numeric resolver), so no need to
00279          * check for the zero-resolvers-available case.
00280          */
00281         if ( ( rc = resmux_try ( mux ) ) != 0 )
00282                 goto err;
00283 
00284         /* Attach parent interface, mortalise self, and return */
00285         intf_plug_plug ( &mux->parent, resolv );
00286         ref_put ( &mux->refcnt );
00287         return 0;
00288 
00289  err:
00290         ref_put ( &mux->refcnt );
00291         return rc;      
00292 }
00293 
00294 /***************************************************************************
00295  *
00296  * Named socket opening
00297  *
00298  ***************************************************************************
00299  */
00300 
00301 /** A named socket */
00302 struct named_socket {
00303         /** Reference counter */
00304         struct refcnt refcnt;
00305         /** Data transfer interface */
00306         struct interface xfer;
00307         /** Name resolution interface */
00308         struct interface resolv;
00309         /** Communication semantics (e.g. SOCK_STREAM) */
00310         int semantics;
00311         /** Stored local socket address, if applicable */
00312         struct sockaddr local;
00313         /** Stored local socket address exists */
00314         int have_local;
00315 };
00316 
00317 /**
00318  * Terminate named socket opener
00319  *
00320  * @v named             Named socket
00321  * @v rc                Reason for termination
00322  */
00323 static void named_close ( struct named_socket *named, int rc ) {
00324         /* Shut down interfaces */
00325         intf_shutdown ( &named->resolv, rc );
00326         intf_shutdown ( &named->xfer, rc );
00327 }
00328 
00329 /**
00330  * Check flow control window
00331  *
00332  * @v named             Named socket
00333  * @ret len             Length of window
00334  */
00335 static size_t named_window ( struct named_socket *named __unused ) {
00336         /* Not ready for data until we have redirected away */
00337         return 0;
00338 }
00339 
00340 /** Named socket opener data transfer interface operations */
00341 static struct interface_operation named_xfer_ops[] = {
00342         INTF_OP ( xfer_window, struct named_socket *, named_window ),
00343         INTF_OP ( intf_close, struct named_socket *, named_close ),
00344 };
00345 
00346 /** Named socket opener data transfer interface descriptor */
00347 static struct interface_descriptor named_xfer_desc =
00348         INTF_DESC_PASSTHRU ( struct named_socket, xfer, named_xfer_ops,
00349                              resolv );
00350 
00351 /**
00352  * Name resolved
00353  *
00354  * @v named             Named socket
00355  * @v sa                Completed socket address
00356  */
00357 static void named_resolv_done ( struct named_socket *named,
00358                                 struct sockaddr *sa ) {
00359         int rc;
00360 
00361         /* Nullify data transfer interface */
00362         intf_nullify ( &named->xfer );
00363 
00364         /* Redirect data-xfer interface */
00365         if ( ( rc = xfer_redirect ( &named->xfer, LOCATION_SOCKET,
00366                                     named->semantics, sa,
00367                                     ( named->have_local ?
00368                                       &named->local : NULL ) ) ) != 0 ) {
00369                 /* Redirection failed - do not unplug data-xfer interface */
00370                 DBGC ( named, "NAMED %p could not redirect: %s\n",
00371                        named, strerror ( rc ) );
00372         } else {
00373                 /* Redirection succeeded - unplug data-xfer interface */
00374                 DBGC ( named, "NAMED %p redirected successfully\n", named );
00375                 intf_unplug ( &named->xfer );
00376         }
00377 
00378         /* Terminate named socket opener */
00379         named_close ( named, rc );
00380 }
00381 
00382 /** Named socket opener resolver interface operations */
00383 static struct interface_operation named_resolv_op[] = {
00384         INTF_OP ( intf_close, struct named_socket *, named_close ),
00385         INTF_OP ( resolv_done, struct named_socket *, named_resolv_done ),
00386 };
00387 
00388 /** Named socket opener resolver interface descriptor */
00389 static struct interface_descriptor named_resolv_desc =
00390         INTF_DESC_PASSTHRU ( struct named_socket, resolv, named_resolv_op,
00391                              xfer );
00392 
00393 /**
00394  * Open named socket
00395  *
00396  * @v semantics         Communication semantics (e.g. SOCK_STREAM)
00397  * @v peer              Peer socket address to complete
00398  * @v name              Name to resolve
00399  * @v local             Local socket address, or NULL
00400  * @ret rc              Return status code
00401  */
00402 int xfer_open_named_socket ( struct interface *xfer, int semantics,
00403                              struct sockaddr *peer, const char *name,
00404                              struct sockaddr *local ) {
00405         struct named_socket *named;
00406         int rc;
00407 
00408         /* Allocate and initialise structure */
00409         named = zalloc ( sizeof ( *named ) );
00410         if ( ! named )
00411                 return -ENOMEM;
00412         ref_init ( &named->refcnt, NULL );
00413         intf_init ( &named->xfer, &named_xfer_desc, &named->refcnt );
00414         intf_init ( &named->resolv, &named_resolv_desc, &named->refcnt );
00415         named->semantics = semantics;
00416         if ( local ) {
00417                 memcpy ( &named->local, local, sizeof ( named->local ) );
00418                 named->have_local = 1;
00419         }
00420 
00421         DBGC ( named, "NAMED %p opening \"%s\"\n",
00422                named, name );
00423 
00424         /* Start name resolution */
00425         if ( ( rc = resolv ( &named->resolv, name, peer ) ) != 0 )
00426                 goto err;
00427 
00428         /* Attach parent interface, mortalise self, and return */
00429         intf_plug_plug ( &named->xfer, xfer );
00430         ref_put ( &named->refcnt );
00431         return 0;
00432 
00433  err:
00434         ref_put ( &named->refcnt );
00435         return rc;
00436 }