root/lib/libsa/net.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sendudp
  2. readudp
  3. sendrecv
  4. inet_addr
  5. inet_ntoa
  6. intoa
  7. number
  8. ip_convertaddr

    1 /*      $OpenBSD: net.c,v 1.13 2003/08/11 06:23:09 deraadt Exp $        */
    2 /*      $NetBSD: net.c,v 1.14 1996/10/13 02:29:02 christos Exp $        */
    3 
    4 /*
    5  * Copyright (c) 1992 Regents of the University of California.
    6  * All rights reserved.
    7  *
    8  * This software was developed by the Computer Systems Engineering group
    9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   10  * contributed to Berkeley.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by the University of
   23  *      California, Lawrence Berkeley Laboratory and its contributors.
   24  * 4. Neither the name of the University nor the names of its contributors
   25  *    may be used to endorse or promote products derived from this software
   26  *    without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   38  * SUCH DAMAGE.
   39  *
   40  * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp  (LBL)
   41  */
   42 
   43 #include <sys/param.h>
   44 #include <sys/socket.h>
   45 
   46 #include <net/if.h>
   47 #include <netinet/in.h>
   48 
   49 #include <netinet/in.h>
   50 #include <netinet/if_ether.h>
   51 #include <netinet/in_systm.h>
   52 #include <netinet/ip.h>
   53 #include <netinet/ip_var.h>
   54 #include <netinet/udp.h>
   55 #include <netinet/udp_var.h>
   56 
   57 #include "stand.h"
   58 #include "net.h"
   59 
   60 /* Caller must leave room for ethernet, ip and udp headers in front!! */
   61 ssize_t
   62 sendudp(struct iodesc *d, void *pkt, size_t len)
   63 {
   64         ssize_t cc;
   65         struct ip *ip;
   66         struct udpiphdr *ui;
   67         struct udphdr *uh;
   68         u_char *ea;
   69         struct ip tip;
   70 
   71 #ifdef NET_DEBUG
   72         if (debug) {
   73                 printf("sendudp: d=%x called.\n", (u_int)d);
   74                 if (d) {
   75                         printf("saddr: %s:%d",
   76                             inet_ntoa(d->myip), ntohs(d->myport));
   77                         printf(" daddr: %s:%d\n",
   78                             inet_ntoa(d->destip), ntohs(d->destport));
   79                 }
   80         }
   81 #endif
   82 
   83         uh = (struct udphdr *)pkt - 1;
   84         ip = (struct ip *)uh - 1;
   85         len += sizeof(*ip) + sizeof(*uh);
   86 
   87         bzero(ip, sizeof(*ip) + sizeof(*uh));
   88 
   89         ip->ip_v = IPVERSION;                   /* half-char */
   90         ip->ip_hl = sizeof(*ip) >> 2;           /* half-char */
   91         ip->ip_len = htons(len);
   92         ip->ip_p = IPPROTO_UDP;                 /* char */
   93         ip->ip_ttl = IP_TTL;                    /* char */
   94         ip->ip_src = d->myip;
   95         ip->ip_dst = d->destip;
   96         ip->ip_sum = in_cksum(ip, sizeof(*ip));  /* short, but special */
   97 
   98         uh->uh_sport = d->myport;
   99         uh->uh_dport = d->destport;
  100         uh->uh_ulen = htons(len - sizeof(*ip));
  101 
  102         /* Calculate checksum (must save and restore ip header) */
  103         tip = *ip;
  104         ui = (struct udpiphdr *)ip;
  105         bzero(ui->ui_x1, sizeof(ui->ui_x1));
  106         ui->ui_len = uh->uh_ulen;
  107         uh->uh_sum = in_cksum(ui, len);
  108         *ip = tip;
  109 
  110         if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 ||
  111             netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask))
  112                 ea = arpwhohas(d, ip->ip_dst);
  113         else
  114                 ea = arpwhohas(d, gateip);
  115 
  116         cc = sendether(d, ip, len, ea, ETHERTYPE_IP);
  117         if (cc < 0)
  118                 return (-1);
  119         if ((size_t)cc != len)
  120                 panic("sendudp: bad write (%d != %d)", cc, len);
  121         return (cc - (sizeof(*ip) + sizeof(*uh)));
  122 }
  123 
  124 /*
  125  * Receive a UDP packet and validate it is for us.
  126  * Caller leaves room for the headers (Ether, IP, UDP)
  127  */
  128 ssize_t
  129 readudp(struct iodesc *d, void *pkt, size_t len, time_t tleft)
  130 {
  131         ssize_t n;
  132         size_t hlen;
  133         struct ip *ip;
  134         struct udphdr *uh;
  135         struct udpiphdr *ui;
  136         struct ip tip;
  137         u_int16_t etype;        /* host order */
  138 
  139 #ifdef NET_DEBUG
  140         if (debug)
  141                 printf("readudp: called\n");
  142 #endif
  143 
  144         uh = (struct udphdr *)pkt - 1;
  145         ip = (struct ip *)uh - 1;
  146 
  147         n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype);
  148         if (n < 0 || (size_t)n < sizeof(*ip) + sizeof(*uh))
  149                 return -1;
  150 
  151         /* Ethernet address checks now in readether() */
  152 
  153         /* Need to respond to ARP requests. */
  154         if (etype == ETHERTYPE_ARP) {
  155                 struct arphdr *ah = (void *)ip;
  156                 if (ah->ar_op == htons(ARPOP_REQUEST)) {
  157                         /* Send ARP reply */
  158                         arp_reply(d, ah);
  159                 }
  160                 return -1;
  161         }
  162 
  163         if (etype != ETHERTYPE_IP) {
  164 #ifdef NET_DEBUG
  165                 if (debug)
  166                         printf("readudp: not IP. ether_type=%x\n", etype);
  167 #endif
  168                 return -1;
  169         }
  170 
  171         /* Check ip header */
  172         if (ip->ip_v != IPVERSION ||
  173             ip->ip_p != IPPROTO_UDP) {  /* half char */
  174 #ifdef NET_DEBUG
  175                 if (debug)
  176                         printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p);
  177 #endif
  178                 return -1;
  179         }
  180 
  181         hlen = ip->ip_hl << 2;
  182         if (hlen < sizeof(*ip) ||
  183             in_cksum(ip, hlen) != 0) {
  184 #ifdef NET_DEBUG
  185                 if (debug)
  186                         printf("readudp: short hdr or bad cksum.\n");
  187 #endif
  188                 return -1;
  189         }
  190         NTOHS(ip->ip_len);
  191         if (n < ip->ip_len) {
  192 #ifdef NET_DEBUG
  193                 if (debug)
  194                         printf("readudp: bad length %d < %d.\n", n, ip->ip_len);
  195 #endif
  196                 return -1;
  197         }
  198         if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) {
  199 #ifdef NET_DEBUG
  200                 if (debug) {
  201                         printf("readudp: bad saddr %s != ", inet_ntoa(d->myip));
  202                         printf("%s\n", inet_ntoa(ip->ip_dst));
  203                 }
  204 #endif
  205                 return -1;
  206         }
  207 
  208         /* If there were ip options, make them go away */
  209         if (hlen != sizeof(*ip)) {
  210                 bcopy(((u_char *)ip) + hlen, uh, len - hlen);
  211                 ip->ip_len = sizeof(*ip);
  212                 n -= hlen - sizeof(*ip);
  213         }
  214         if (uh->uh_dport != d->myport) {
  215 #ifdef NET_DEBUG
  216                 if (debug)
  217                         printf("readudp: bad dport %d != %d\n",
  218                                 d->myport, ntohs(uh->uh_dport));
  219 #endif
  220                 return -1;
  221         }
  222 
  223         if (uh->uh_sum) {
  224                 n = ntohs(uh->uh_ulen) + sizeof(*ip);
  225                 if (n > RECV_SIZE - ETHER_SIZE) {
  226                         printf("readudp: huge packet, udp len %ld\n", (long)n);
  227                         return -1;
  228                 }
  229 
  230                 /* Check checksum (must save and restore ip header) */
  231                 tip = *ip;
  232                 ui = (struct udpiphdr *)ip;
  233                 bzero(ui->ui_x1, sizeof(ui->ui_x1));
  234                 ui->ui_len = uh->uh_ulen;
  235                 if (in_cksum(ui, n) != 0) {
  236 #ifdef NET_DEBUG
  237                         if (debug)
  238                                 printf("readudp: bad cksum\n");
  239 #endif
  240                         *ip = tip;
  241                         return -1;
  242                 }
  243                 *ip = tip;
  244         }
  245         NTOHS(uh->uh_dport);
  246         NTOHS(uh->uh_sport);
  247         NTOHS(uh->uh_ulen);
  248         if (uh->uh_ulen < sizeof(*uh)) {
  249 #ifdef NET_DEBUG
  250                 if (debug)
  251                         printf("readudp: bad udp len %d < %d\n",
  252                                 uh->uh_ulen, sizeof(*uh));
  253 #endif
  254                 return -1;
  255         }
  256 
  257         n -= sizeof(*ip) + sizeof(*uh);
  258         return (n);
  259 }
  260 
  261 /*
  262  * Send a packet and wait for a reply, with exponential backoff.
  263  *
  264  * The send routine must return the actual number of bytes written.
  265  *
  266  * The receive routine can indicate success by returning the number of
  267  * bytes read; it can return 0 to indicate EOF; it can return -1 with a
  268  * non-zero errno to indicate failure; finally, it can return -1 with a
  269  * zero errno to indicate it isn't done yet.
  270  */
  271 ssize_t
  272 sendrecv(struct iodesc *d, ssize_t (*sproc)(struct iodesc *, void *, size_t),
  273     void *sbuf, size_t ssize,
  274     ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t),
  275     void *rbuf, size_t rsize)
  276 {
  277         ssize_t cc;
  278         time_t t, tmo, tlast;
  279         long tleft;
  280 
  281 #ifdef NET_DEBUG
  282         if (debug)
  283                 printf("sendrecv: called\n");
  284 #endif
  285 
  286         tmo = MINTMO;
  287         tlast = tleft = 0;
  288         t = getsecs();
  289         for (;;) {
  290                 if (tleft <= 0) {
  291                         if (tmo >= MAXTMO) {
  292                                 errno = ETIMEDOUT;
  293                                 return -1;
  294                         }
  295                         cc = (*sproc)(d, sbuf, ssize);
  296                         if (cc < 0 || (size_t)cc < ssize)
  297                                 panic("sendrecv: short write! (%d < %d)",
  298                                     cc, ssize);
  299 
  300                         tleft = tmo;
  301                         tmo <<= 1;
  302                         if (tmo > MAXTMO)
  303                                 tmo = MAXTMO;
  304                         tlast = t;
  305                 }
  306 
  307                 /* Try to get a packet and process it. */
  308                 cc = (*rproc)(d, rbuf, rsize, tleft);
  309                 /* Return on data, EOF or real error. */
  310                 if (cc != -1 || errno != 0)
  311                         return (cc);
  312 
  313                 /* Timed out or didn't get the packet we're waiting for */
  314                 t = getsecs();
  315                 tleft -= t - tlast;
  316                 tlast = t;
  317         }
  318 }
  319 
  320 /*
  321  * Like inet_addr() in the C library, but we only accept base-10.
  322  * Return values are in network order.
  323  */
  324 n_long
  325 inet_addr(char *cp)
  326 {
  327         u_long val;
  328         int n;
  329         char c;
  330         u_int parts[4];
  331         u_int *pp = parts;
  332 
  333         for (;;) {
  334                 /*
  335                  * Collect number up to ``.''.
  336                  * Values are specified as for C:
  337                  * 0x=hex, 0=octal, other=decimal.
  338                  */
  339                 val = 0;
  340                 while ((c = *cp) != '\0') {
  341                         if (c >= '0' && c <= '9') {
  342                                 val = (val * 10) + (c - '0');
  343                                 cp++;
  344                                 continue;
  345                         }
  346                         break;
  347                 }
  348                 if (*cp == '.') {
  349                         /*
  350                          * Internet format:
  351                          *      a.b.c.d
  352                          *      a.b.c   (with c treated as 16-bits)
  353                          *      a.b     (with b treated as 24 bits)
  354                          */
  355                         if (pp >= parts + 3 || val > 0xff)
  356                                 goto bad;
  357                         *pp++ = val, cp++;
  358                 } else
  359                         break;
  360         }
  361         /*
  362          * Check for trailing characters.
  363          */
  364         if (*cp != '\0')
  365                 goto bad;
  366 
  367         /*
  368          * Concoct the address according to
  369          * the number of parts specified.
  370          */
  371         n = pp - parts + 1;
  372         switch (n) {
  373 
  374         case 1:                         /* a -- 32 bits */
  375                 break;
  376 
  377         case 2:                         /* a.b -- 8.24 bits */
  378                 if (val > 0xffffff)
  379                         goto bad;
  380                 val |= parts[0] << 24;
  381                 break;
  382 
  383         case 3:                         /* a.b.c -- 8.8.16 bits */
  384                 if (val > 0xffff)
  385                         goto bad;
  386                 val |= (parts[0] << 24) | (parts[1] << 16);
  387                 break;
  388 
  389         case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
  390                 if (val > 0xff)
  391                         goto bad;
  392                 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
  393                 break;
  394         }
  395 
  396         return (htonl(val));
  397  bad:
  398         return (htonl(INADDR_NONE));
  399 }
  400 
  401 char *
  402 inet_ntoa(struct in_addr ia)
  403 {
  404         return (intoa(ia.s_addr));
  405 }
  406 
  407 /* Similar to inet_ntoa() */
  408 char *
  409 intoa(n_long addr)
  410 {
  411         char *cp;
  412         u_int byte;
  413         int n;
  414         static char buf[sizeof(".255.255.255.255")];
  415 
  416         NTOHL(addr);
  417         cp = &buf[sizeof buf];
  418         *--cp = '\0';
  419 
  420         n = 4;
  421         do {
  422                 byte = addr & 0xff;
  423                 *--cp = byte % 10 + '0';
  424                 byte /= 10;
  425                 if (byte > 0) {
  426                         *--cp = byte % 10 + '0';
  427                         byte /= 10;
  428                         if (byte > 0)
  429                                 *--cp = byte + '0';
  430                 }
  431                 *--cp = '.';
  432                 addr >>= 8;
  433         } while (--n > 0);
  434 
  435         return (cp+1);
  436 }
  437 
  438 static char *
  439 number(char *s, int *n)
  440 {
  441         for (*n = 0; isdigit(*s); s++)
  442                 *n = (*n * 10) + *s - '0';
  443         return s;
  444 }
  445 
  446 n_long
  447 ip_convertaddr(char *p)
  448 {
  449 #define IP_ANYADDR      0
  450         n_long addr = 0, n;
  451 
  452         if (p == (char *)0 || *p == '\0')
  453                 return IP_ANYADDR;
  454         p = number(p, &n);
  455         addr |= (n << 24) & 0xff000000;
  456         if (*p == '\0' || *p++ != '.')
  457                 return IP_ANYADDR;
  458         p = number(p, &n);
  459         addr |= (n << 16) & 0xff0000;
  460         if (*p == '\0' || *p++ != '.')
  461                 return IP_ANYADDR;
  462         p = number(p, &n);
  463         addr |= (n << 8) & 0xff00;
  464         if (*p == '\0' || *p++ != '.')
  465                 return IP_ANYADDR;
  466         p = number(p, &n);
  467         addr |= n & 0xff;
  468         if (*p != '\0')
  469                 return IP_ANYADDR;
  470 
  471         return htonl(addr);
  472 }

/* [<][>][^][v][top][bottom][index][help] */