"Fossies" - the Fresh Open Source Software Archive

Member "hitch-1.5.2/src/foreign/vsa.c" (27 Aug 2019, 11285 Bytes) of package /linux/www/hitch-1.5.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vsa.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.4.8_vs_1.5.0.

    1 /*-
    2  * Copyright (c) 2013-2015 Varnish Software AS
    3  * All rights reserved.
    4  *
    5  * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * Struct sockaddr_* is not even close to a convenient API.
   29  *
   30  * These functions try to mitigate the madness, at the cost of actually
   31  * knowing something about address families.
   32  */
   33 
   34 #include "config.h"
   35 
   36 #include <string.h>
   37 #include <stdlib.h>
   38 #include <sys/socket.h>
   39 #include <sys/un.h>
   40 #include <netinet/in.h>
   41 
   42 #include "vas.h"
   43 #include "vsa.h"
   44 #include "miniobj.h"
   45 
   46 /*
   47  * Struct sockaddr{|_in|_in6|_storage} is absolutely the worst data
   48  * structure I have ever seen gold-plated in international standards.
   49  *
   50  * Network addresses have multiple different forms, many fewer today
   51  * than in last century, but imagine that in addition to IPv4 and IPv6
   52  * we had 40 other protocols.  Actually, you don't need to imagine that
   53  * just count the AF_* macros in /usr/include/sys/socket.h.
   54  *
   55  * So what do we pass the kernel API for an address to bind(2), connect(2) &
   56  * listen(2) etc. etc ?
   57  *
   58  * We could define a struct which is big enough to hold any and all
   59  * of these addresses.  That would make it a fixed size argument.
   60  * obviously the struct would have to be something like:
   61  *  struct bla {
   62  *      int family;
   63  *      char address[MAX_ADDR_LEN];
   64  *  }
   65  * and MAX_ADDR_LEN would have to be quite large, 128 byte or so.
   66  *
   67  * Back in last century that was TOTALLY unacceptable waste of space.
   68  *
   69  * The way which was chosen instead, was to make a "generic" address,
   70  * and have per protocol "specific" addresses, and pass the length
   71  * argument explicitly to the KPI functions.
   72  *
   73  * The generic address was called "struct sockaddr", and the specific
   74  * were called "struct sockaddr_${whatever}".  All of these must have
   75  * a "family" field as first element, so the kernel can figure out
   76  * which protocol it is.
   77  *
   78  * The generic struct sockaddr was made big enough for all protocols
   79  * supported in the kernel, so it would have different sizes depending
   80  * on your machine and kernel configuration.
   81  *
   82  * However, that allowed you to write protocol-agnostic programs, by
   83  * using "struct sockaddr" throughout, and relying on libray APIs for
   84  * things like name to address (and vice versa) resolution, and since
   85  * nobody were in the business of shipping random UNIX binaries around
   86  * the lack of binary portability didn't matter.
   87  *
   88  * Along the way the BSD people figured out that it was a bother
   89  * to carry the length argument separately, and added that to the
   90  * format of sockaddr, but other groups found this unclean, as
   91  * the length was already an explicit paramter.
   92  *
   93  * The net result of this is that your "portable" code, must take
   94  * care to handle the "sa_len" member on kernels which have it,
   95  * while still tracking the separate length argument for all other
   96  * kernels.
   97  *
   98  * Needless to say, there were no neat #define to tell you which
   99  * was which, so each programmer found a different heuristic to
  100  * decide, often not understanding it fully, which caused the kind
  101  * of portability issues which lead to the autocrap tools.
  102  *
  103  * Then all the other protocols died, we were left with IP and
  104  * life were good, the dot-com madness multiplied the IT-business
  105  * by a factor 1000, by making any high-school student who had
  106  * programmed PERL for 6 weeks a "senior web-programmer".
  107  *
  108  * Next IPv6 happened, in a rush even, (no seriously, I'm not kidding!),
  109  * and since IPv6 addresses were HUGE, like 16 bytes HUGE, the generic
  110  * struct sockaddr was not increased in size.
  111  *
  112  * At least "not yet", because it would break all the shitty code written
  113  * by the dot-com generation.
  114  *
  115  * Nobody used IPv6 anyway so that didn't matter that much.
  116  *
  117  * Then people actually started using IPv6 and its struct sockaddr_in6,
  118  * and realized that all the code which used "struct sockaddr" to allocate
  119  * space at compile time were broken.
  120  *
  121  * Some people took to using sockaddr_in6, since that was known to
  122  * be big enough for both IPv4 and IPv6, but "purist" found that
  123  * ugly and "prone to future trouble".
  124  *
  125  * So instead they came up with a "clean solution":  The added
  126  * "struct sockaddr_storage" which is defined to be "Large enough
  127  * to accommodate all supported protocol-specific address structures".
  128  *
  129  * Since we cannot possibly know what zany protocols will exist in
  130  * the future, and since some people think that we will add future
  131  * protocols, while retaining ABI compatibility, (totally overlooking
  132  * the fact that no code for name-resolution supports that) it is
  133  * usually defined so it can cope with 128 byte addresses.
  134  *
  135  * Does that ring a bell ?
  136  *
  137  * Only, not quite:  Remember that all APIs require you to track
  138  * the address and the length separately, so you only get the
  139  * size of the specific protocols sockaddr_${whatever} from API
  140  * functions, not a full sockaddr_storage, and besides the
  141  * prototype for the KPI is still "struct sockaddr *", so you
  142  * cannot gain C type-safety back by using sockaddr_storage
  143  * as the "generic network address" type.
  144  *
  145  * So we have come full circle, while causing maximum havoc along
  146  * the way and for the forseeable future.
  147  *
  148  * Do I need to tell you that static code analysis tools have a
  149  * really hard time coping with this, and that they give a lot of
  150  * false negatives which confuse people ?
  151  *
  152  * I have decided to try to contain this crap in this single
  153  * source-file, with only minimum leakage into the rest of Varnish,
  154  * which will only know of pointers to "struct suckaddr", the naming
  155  * of which is my of the historical narrative above.
  156  *
  157  * And you don't need to take my word for this, you can see it all
  158  * in various #include files on your own system.   If you are on
  159  * a Solaris derivative, don't miss the beautiful horror hidden in the
  160  * variant definition of IPv6 addresses between kernel and userland.
  161  *
  162  */
  163 
  164 struct suckaddr {
  165     unsigned            magic;
  166 #define SUCKADDR_MAGIC          0x4b1e9335
  167     union {
  168         struct sockaddr     sa;
  169         struct sockaddr_in  sa4;
  170         struct sockaddr_in6 sa6;
  171         struct sockaddr_un  sun;
  172     };
  173 };
  174 
  175 const int vsa_suckaddr_len = sizeof(struct suckaddr);
  176 
  177 /*
  178  * This VRT interface is for the VCC generated ACL code, which needs
  179  * to know the address family and a pointer to the actual address.
  180  */
  181 
  182 int
  183 VRT_VSA_GetPtr(const struct suckaddr *sua, const unsigned char ** dst)
  184 {
  185 
  186     AN(dst);
  187     if (sua == NULL)
  188         return (-1);
  189     CHECK_OBJ_NOTNULL(sua, SUCKADDR_MAGIC);
  190 
  191     switch (sua->sa.sa_family) {
  192     case PF_INET:
  193         assert(sua->sa.sa_family == sua->sa4.sin_family);
  194         *dst = (const unsigned char *)&sua->sa4.sin_addr;
  195         return (sua->sa4.sin_family);
  196     case PF_INET6:
  197         assert(sua->sa.sa_family == sua->sa6.sin6_family);
  198         *dst = (const unsigned char *)&sua->sa6.sin6_addr;
  199         return (sua->sa6.sin6_family);
  200     case PF_UNIX:
  201         assert(sua->sa.sa_family == sua->sun.sun_family);
  202         *dst = (const unsigned char *)&sua->sun.sun_path;
  203         return (sua->sun.sun_family);
  204     default:
  205         *dst = NULL;
  206         return (-1);
  207     }
  208 }
  209 
  210 /*
  211  * Malloc a suckaddr from a sockaddr of some kind.
  212  */
  213 
  214 struct suckaddr *
  215 VSA_Malloc(const void *s, unsigned  sal)
  216 {
  217     struct suckaddr *sua = NULL;
  218     const struct sockaddr *sa = s;
  219     unsigned l = 0;
  220 
  221     AN(s);
  222     switch (sa->sa_family) {
  223     case PF_INET:
  224         if (sal == sizeof sua->sa4)
  225             l = sal;
  226         break;
  227     case PF_INET6:
  228         if (sal == sizeof sua->sa6)
  229             l = sal;
  230         break;
  231     case PF_UNIX:
  232         if (sal == sizeof sua->sun)
  233             l = sal;
  234         break;
  235     default:
  236         break;
  237     }
  238     if (l != 0) {
  239         ALLOC_OBJ(sua, SUCKADDR_MAGIC);
  240         if (sua != NULL)
  241             memcpy(&sua->sa, s, l);
  242     }
  243     return (sua);
  244 }
  245 
  246 /* 'd' SHALL point to vsa_suckaddr_len aligned bytes of storage */
  247 struct suckaddr *
  248 VSA_Build(void *d, const void *s, unsigned sal)
  249 {
  250     struct suckaddr *sua = d;
  251     const struct sockaddr *sa = s;
  252     unsigned l = 0;
  253 
  254     AN(d);
  255     AN(s);
  256     switch (sa->sa_family) {
  257     case PF_INET:
  258         if (sal == sizeof sua->sa4)
  259             l = sal;
  260         break;
  261     case PF_INET6:
  262         if (sal == sizeof sua->sa6)
  263             l = sal;
  264         break;
  265     case PF_UNIX:
  266         if (sal == sizeof sua->sun)
  267             l = sal;
  268         break;
  269     default:
  270         break;
  271     }
  272     if (l != 0) {
  273         memset(sua, 0, sizeof *sua);
  274         sua->magic = SUCKADDR_MAGIC;
  275         memcpy(&sua->sa, s, l);
  276         return (sua);
  277     }
  278     return (NULL);
  279 }
  280 
  281 const void *
  282 VSA_Get_Sockaddr(const struct suckaddr *sua, socklen_t *sl)
  283 {
  284 
  285     CHECK_OBJ_NOTNULL(sua, SUCKADDR_MAGIC);
  286     AN(sl);
  287     switch (sua->sa.sa_family) {
  288     case PF_INET:
  289         *sl = sizeof sua->sa4;
  290         break;
  291     case PF_INET6:
  292         *sl = sizeof sua->sa6;
  293         break;
  294     case PF_UNIX:
  295         *sl = sizeof sua->sun;
  296         break;
  297     default:
  298         return (NULL);
  299     }
  300     return (&sua->sa);
  301 }
  302 
  303 int
  304 VSA_Get_Proto(const struct suckaddr *sua)
  305 {
  306 
  307     CHECK_OBJ_NOTNULL(sua, SUCKADDR_MAGIC);
  308     return (sua->sa.sa_family);
  309 }
  310 
  311 int
  312 VSA_Sane(const struct suckaddr *sua)
  313 {
  314     CHECK_OBJ_NOTNULL(sua, SUCKADDR_MAGIC);
  315 
  316     switch (sua->sa.sa_family) {
  317     case PF_INET:
  318     case PF_INET6:
  319     case PF_UNIX:
  320         return (1);
  321     default:
  322         return (0);
  323     }
  324 }
  325 
  326 int
  327 VSA_Compare(const struct suckaddr *sua1, const struct suckaddr *sua2)
  328 {
  329 
  330     CHECK_OBJ_NOTNULL(sua1, SUCKADDR_MAGIC);
  331     CHECK_OBJ_NOTNULL(sua2, SUCKADDR_MAGIC);
  332     return (memcmp(sua1, sua2, vsa_suckaddr_len));
  333 }
  334 
  335 int
  336 VSA_Compare_IP(const struct suckaddr *sua1, const struct suckaddr *sua2)
  337 {
  338 
  339     assert(VSA_Sane(sua1));
  340     assert(VSA_Sane(sua2));
  341 
  342     if (sua1->sa.sa_family != sua2->sa.sa_family)
  343         return (-1);
  344 
  345     switch (sua1->sa.sa_family) {
  346     case PF_INET:
  347         return (memcmp(&sua1->sa4.sin_addr,
  348             &sua2->sa4.sin_addr, sizeof(struct in_addr)));
  349     case PF_INET6:
  350         return (memcmp(&sua1->sa6.sin6_addr,
  351             &sua2->sa6.sin6_addr, sizeof(struct in6_addr)));
  352     default:
  353         WRONG("Just plain insane");
  354     }
  355     return(-1);
  356 }
  357 
  358 struct suckaddr *
  359 VSA_Clone(const struct suckaddr *sua)
  360 {
  361     struct suckaddr *sua2;
  362 
  363     assert(VSA_Sane(sua));
  364     sua2 = calloc(1, vsa_suckaddr_len);
  365     XXXAN(sua2);
  366     memcpy(sua2, sua, vsa_suckaddr_len);
  367     return (sua2);
  368 }
  369 
  370 unsigned
  371 VSA_Port(const struct suckaddr *sua)
  372 {
  373 
  374     CHECK_OBJ_NOTNULL(sua, SUCKADDR_MAGIC);
  375     switch (sua->sa.sa_family) {
  376     case PF_INET:
  377         return (ntohs(sua->sa4.sin_port));
  378     case PF_INET6:
  379         return (ntohs(sua->sa6.sin6_port));
  380     default:
  381         return (0);
  382     }
  383 }