Annotation of embedaddon/dhcp/common/packet.c, revision 1.1.1.1

1.1       misho       1: /* packet.c
                      2: 
                      3:    Packet assembly code, originally contributed by Archie Cobbs. */
                      4: 
                      5: /*
1.1.1.1 ! misho       6:  * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
        !             7:  * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
1.1       misho       8:  * Copyright (c) 1996-2003 by Internet Software Consortium
                      9:  *
                     10:  * Permission to use, copy, modify, and distribute this software for any
                     11:  * purpose with or without fee is hereby granted, provided that the above
                     12:  * copyright notice and this permission notice appear in all copies.
                     13:  *
                     14:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
                     15:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     16:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
                     17:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     18:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     19:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
                     20:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     21:  *
                     22:  *   Internet Systems Consortium, Inc.
                     23:  *   950 Charter Street
                     24:  *   Redwood City, CA 94063
                     25:  *   <info@isc.org>
                     26:  *   https://www.isc.org/
                     27:  *
                     28:  * This code was originally contributed by Archie Cobbs, and is still
                     29:  * very similar to that contribution, although the packet checksum code
                     30:  * has been hacked significantly with the help of quite a few ISC DHCP
                     31:  * users, without whose gracious and thorough help the checksum code would
                     32:  * still be disabled.
                     33:  */
                     34: 
                     35: #include "dhcpd.h"
                     36: 
                     37: #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)
                     38: #include "includes/netinet/ip.h"
                     39: #include "includes/netinet/udp.h"
                     40: #include "includes/netinet/if_ether.h"
                     41: #endif /* PACKET_ASSEMBLY || PACKET_DECODING */
                     42: 
                     43: /* Compute the easy part of the checksum on a range of bytes. */
                     44: 
                     45: u_int32_t checksum (buf, nbytes, sum)
                     46:        unsigned char *buf;
                     47:        unsigned nbytes;
                     48:        u_int32_t sum;
                     49: {
                     50:        unsigned i;
                     51: 
                     52: #ifdef DEBUG_CHECKSUM
                     53:        log_debug ("checksum (%x %d %x)", buf, nbytes, sum);
                     54: #endif
                     55: 
                     56:        /* Checksum all the pairs of bytes first... */
                     57:        for (i = 0; i < (nbytes & ~1U); i += 2) {
                     58: #ifdef DEBUG_CHECKSUM_VERBOSE
                     59:                log_debug ("sum = %x", sum);
                     60: #endif
                     61:                sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i)));
                     62:                /* Add carry. */
                     63:                if (sum > 0xFFFF)
                     64:                        sum -= 0xFFFF;
                     65:        }       
                     66: 
                     67:        /* If there's a single byte left over, checksum it, too.   Network
                     68:           byte order is big-endian, so the remaining byte is the high byte. */
                     69:        if (i < nbytes) {
                     70: #ifdef DEBUG_CHECKSUM_VERBOSE
                     71:                log_debug ("sum = %x", sum);
                     72: #endif
                     73:                sum += buf [i] << 8;
                     74:                /* Add carry. */
                     75:                if (sum > 0xFFFF)
                     76:                        sum -= 0xFFFF;
                     77:        }
                     78:        
                     79:        return sum;
                     80: }
                     81: 
                     82: /* Finish computing the checksum, and then put it into network byte order. */
                     83: 
                     84: u_int32_t wrapsum (sum)
                     85:        u_int32_t sum;
                     86: {
                     87: #ifdef DEBUG_CHECKSUM
                     88:        log_debug ("wrapsum (%x)", sum);
                     89: #endif
                     90: 
                     91:        sum = ~sum & 0xFFFF;
                     92: #ifdef DEBUG_CHECKSUM_VERBOSE
                     93:        log_debug ("sum = %x", sum);
                     94: #endif
                     95:        
                     96: #ifdef DEBUG_CHECKSUM
                     97:        log_debug ("wrapsum returns %x", htons (sum));
                     98: #endif
                     99:        return htons(sum);
                    100: }
                    101: 
                    102: #ifdef PACKET_ASSEMBLY
                    103: void assemble_hw_header (interface, buf, bufix, to)
                    104:        struct interface_info *interface;
                    105:        unsigned char *buf;
                    106:        unsigned *bufix;
                    107:        struct hardware *to;
                    108: {
1.1.1.1 ! misho     109:        switch (interface->hw_address.hbuf[0]) {
        !           110: #if defined(HAVE_TR_SUPPORT)
        !           111:        case HTYPE_IEEE802:
        !           112:                assemble_tr_header(interface, buf, bufix, to);
        !           113:                break;
1.1       misho     114: #endif
                    115: #if defined (DEC_FDDI)
1.1.1.1 ! misho     116:        case HTYPE_FDDI:
        !           117:                assemble_fddi_header(interface, buf, bufix, to);
        !           118:                break;
1.1       misho     119: #endif
1.1.1.1 ! misho     120:        case HTYPE_INFINIBAND:
        !           121:                log_error("Attempt to assemble hw header for infiniband");
        !           122:                break;
        !           123:        case HTYPE_ETHER:
        !           124:        default:
        !           125:                assemble_ethernet_header(interface, buf, bufix, to);
        !           126:                break;
        !           127:        }
1.1       misho     128: }
                    129: 
                    130: /* UDP header and IP header assembled together for convenience. */
                    131: 
                    132: void assemble_udp_ip_header (interface, buf, bufix,
                    133:                             from, to, port, data, len)
                    134:        struct interface_info *interface;
                    135:        unsigned char *buf;
                    136:        unsigned *bufix;
                    137:        u_int32_t from;
                    138:        u_int32_t to;
                    139:        u_int32_t port;
                    140:        unsigned char *data;
                    141:        unsigned len;
                    142: {
                    143:        struct ip ip;
                    144:        struct udphdr udp;
                    145: 
                    146:        memset (&ip, 0, sizeof ip);
                    147: 
                    148:        /* Fill out the IP header */
                    149:        IP_V_SET (&ip, 4);
                    150:        IP_HL_SET (&ip, 20);
                    151:        ip.ip_tos = IPTOS_LOWDELAY;
                    152:        ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
                    153:        ip.ip_id = 0;
                    154:        ip.ip_off = 0;
                    155:        ip.ip_ttl = 128;
                    156:        ip.ip_p = IPPROTO_UDP;
                    157:        ip.ip_sum = 0;
                    158:        ip.ip_src.s_addr = from;
                    159:        ip.ip_dst.s_addr = to;
                    160:        
                    161:        /* Checksum the IP header... */
                    162:        ip.ip_sum = wrapsum (checksum ((unsigned char *)&ip, sizeof ip, 0));
                    163:        
                    164:        /* Copy the ip header into the buffer... */
                    165:        memcpy (&buf [*bufix], &ip, sizeof ip);
                    166:        *bufix += sizeof ip;
                    167: 
                    168:        /* Fill out the UDP header */
                    169:        udp.uh_sport = local_port;              /* XXX */
                    170:        udp.uh_dport = port;                    /* XXX */
                    171:        udp.uh_ulen = htons(sizeof(udp) + len);
                    172:        memset (&udp.uh_sum, 0, sizeof udp.uh_sum);
                    173: 
                    174:        /* Compute UDP checksums, including the ``pseudo-header'', the UDP
                    175:           header and the data. */
                    176: 
                    177:        udp.uh_sum =
                    178:                wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
                    179:                                   checksum (data, len, 
                    180:                                             checksum ((unsigned char *)
                    181:                                                       &ip.ip_src,
                    182:                                                       2 * sizeof ip.ip_src,
                    183:                                                       IPPROTO_UDP +
                    184:                                                       (u_int32_t)
                    185:                                                       ntohs (udp.uh_ulen)))));
                    186: 
                    187:        /* Copy the udp header into the buffer... */
                    188:        memcpy (&buf [*bufix], &udp, sizeof udp);
                    189:        *bufix += sizeof udp;
                    190: }
                    191: #endif /* PACKET_ASSEMBLY */
                    192: 
                    193: #ifdef PACKET_DECODING
                    194: /* Decode a hardware header... */
1.1.1.1 ! misho     195: /* Support for ethernet, TR and FDDI
        !           196:  * Doesn't support infiniband yet as the supported oses shouldn't get here
        !           197:  */
1.1       misho     198: 
                    199: ssize_t decode_hw_header (interface, buf, bufix, from)
                    200:      struct interface_info *interface;
                    201:      unsigned char *buf;
                    202:      unsigned bufix;
                    203:      struct hardware *from;
                    204: {
1.1.1.1 ! misho     205:        switch(interface->hw_address.hbuf[0]) {
1.1       misho     206: #if defined (HAVE_TR_SUPPORT)
1.1.1.1 ! misho     207:        case HTYPE_IEEE802:
        !           208:                return (decode_tr_header(interface, buf, bufix, from));
1.1       misho     209: #endif
                    210: #if defined (DEC_FDDI)
1.1.1.1 ! misho     211:        case HTYPE_FDDI:
        !           212:                return (decode_fddi_header(interface, buf, bufix, from));
1.1       misho     213: #endif
1.1.1.1 ! misho     214:        case HTYPE_INFINIBAND:
        !           215:                log_error("Attempt to decode hw header for infiniband");
        !           216:                return (0);
        !           217:        case HTYPE_ETHER:
        !           218:        default:
        !           219:                return (decode_ethernet_header(interface, buf, bufix, from));
        !           220:        }
1.1       misho     221: }
                    222: 
                    223: /* UDP header and IP header decoded together for convenience. */
                    224: 
                    225: ssize_t
                    226: decode_udp_ip_header(struct interface_info *interface,
                    227:                     unsigned char *buf, unsigned bufix,
                    228:                     struct sockaddr_in *from, unsigned buflen,
                    229:                     unsigned *rbuflen)
                    230: {
                    231:   unsigned char *data;
                    232:   struct ip ip;
                    233:   struct udphdr udp;
                    234:   unsigned char *upp, *endbuf;
                    235:   u_int32_t ip_len, ulen, pkt_len;
                    236:   u_int32_t sum, usum;
                    237:   static int ip_packets_seen;
                    238:   static int ip_packets_bad_checksum;
                    239:   static int udp_packets_seen;
                    240:   static int udp_packets_bad_checksum;
                    241:   static int udp_packets_length_checked;
                    242:   static int udp_packets_length_overflow;
                    243:   unsigned len;
                    244: 
                    245:   /* Designate the end of the input buffer for bounds checks. */
                    246:   endbuf = buf + bufix + buflen;
                    247: 
                    248:   /* Assure there is at least an IP header there. */
                    249:   if ((buf + bufix + sizeof(ip)) > endbuf)
                    250:          return -1;
                    251: 
                    252:   /* Copy the IP header into a stack aligned structure for inspection.
                    253:    * There may be bits in the IP header that we're not decoding, so we
                    254:    * copy out the bits we grok and skip ahead by ip.ip_hl * 4.
                    255:    */
                    256:   upp = buf + bufix;
                    257:   memcpy(&ip, upp, sizeof(ip));
                    258:   ip_len = (*upp & 0x0f) << 2;
                    259:   upp += ip_len;
                    260: 
                    261:   /* Check the IP packet length. */
                    262:   pkt_len = ntohs(ip.ip_len);
                    263:   if (pkt_len > buflen)
                    264:        return -1;
                    265: 
                    266:   /* Assure after ip_len bytes that there is enough room for a UDP header. */
                    267:   if ((upp + sizeof(udp)) > endbuf)
                    268:          return -1;
                    269: 
                    270:   /* Copy the UDP header into a stack aligned structure for inspection. */
                    271:   memcpy(&udp, upp, sizeof(udp));
                    272: 
                    273: #ifdef USERLAND_FILTER
                    274:   /* Is it a UDP packet? */
                    275:   if (ip.ip_p != IPPROTO_UDP)
                    276:          return -1;
                    277: 
                    278:   /* Is it to the port we're serving? */
                    279:   if (udp.uh_dport != local_port)
                    280:          return -1;
                    281: #endif /* USERLAND_FILTER */
                    282: 
                    283:   ulen = ntohs(udp.uh_ulen);
                    284:   if (ulen < sizeof(udp))
                    285:        return -1;
                    286: 
                    287:   udp_packets_length_checked++;
                    288:   if ((upp + ulen) > endbuf) {
                    289:        udp_packets_length_overflow++;
                    290:        if ((udp_packets_length_checked > 4) &&
                    291:            ((udp_packets_length_checked /
                    292:              udp_packets_length_overflow) < 2)) {
                    293:                log_info("%d udp packets in %d too long - dropped",
                    294:                         udp_packets_length_overflow,
                    295:                         udp_packets_length_checked);
                    296:                udp_packets_length_overflow = 0;
                    297:                udp_packets_length_checked = 0;
                    298:        }
                    299:        return -1;
                    300:   }
                    301: 
                    302:   if ((ulen < sizeof(udp)) || ((upp + ulen) > endbuf))
                    303:        return -1;
                    304: 
                    305:   /* Check the IP header checksum - it should be zero. */
                    306:   ++ip_packets_seen;
                    307:   if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
                    308:          ++ip_packets_bad_checksum;
                    309:          if (ip_packets_seen > 4 &&
                    310:              (ip_packets_seen / ip_packets_bad_checksum) < 2) {
                    311:                  log_info ("%d bad IP checksums seen in %d packets",
                    312:                            ip_packets_bad_checksum, ip_packets_seen);
                    313:                  ip_packets_seen = ip_packets_bad_checksum = 0;
                    314:          }
                    315:          return -1;
                    316:   }
                    317: 
                    318:   /* Copy out the IP source address... */
                    319:   memcpy(&from->sin_addr, &ip.ip_src, 4);
                    320: 
                    321:   /* Compute UDP checksums, including the ``pseudo-header'', the UDP
                    322:      header and the data.   If the UDP checksum field is zero, we're
                    323:      not supposed to do a checksum. */
                    324: 
                    325:   data = upp + sizeof(udp);
                    326:   len = ulen - sizeof(udp);
                    327: 
                    328:   usum = udp.uh_sum;
                    329:   udp.uh_sum = 0;
                    330: 
                    331:   /* XXX: We have to pass &udp, because we have to zero the checksum
                    332:    * field before calculating the sum...'upp' isn't zeroed.
                    333:    */
                    334:   sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
                    335:                         checksum(data, len,
                    336:                                  checksum((unsigned char *)&ip.ip_src,
                    337:                                           8, IPPROTO_UDP + ulen))));
                    338: 
                    339:   udp_packets_seen++;
                    340:   if (usum && usum != sum) {
                    341:          udp_packets_bad_checksum++;
                    342:          if (udp_packets_seen > 4 &&
                    343:              (udp_packets_seen / udp_packets_bad_checksum) < 2) {
                    344:                  log_info ("%d bad udp checksums in %d packets",
                    345:                            udp_packets_bad_checksum, udp_packets_seen);
                    346:                  udp_packets_seen = udp_packets_bad_checksum = 0;
                    347:          }
                    348:          return -1;
                    349:   }
                    350: 
                    351:   /* Copy out the port... */
                    352:   memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
                    353: 
                    354:   /* Save the length of the UDP payload. */
                    355:   if (rbuflen != NULL)
                    356:        *rbuflen = len;
                    357: 
                    358:   /* Return the index to the UDP payload. */
                    359:   return ip_len + sizeof udp;
                    360: }
                    361: #endif /* PACKET_DECODING */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>