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

1.1       misho       1: /* lpf.c
                      2: 
                      3:    Linux packet filter code, contributed by Brian Murrel at Interlinx
                      4:    Support Services in Vancouver, B.C. */
                      5: 
                      6: /*
                      7:  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
                      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: 
                     29: #include "dhcpd.h"
                     30: #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
                     31: #include <sys/ioctl.h>
                     32: #include <sys/uio.h>
                     33: #include <errno.h>
                     34: 
                     35: #include <asm/types.h>
                     36: #include <linux/filter.h>
                     37: #include <linux/if_ether.h>
                     38: #include <netinet/in_systm.h>
                     39: #include <net/if_packet.h>
                     40: #include "includes/netinet/ip.h"
                     41: #include "includes/netinet/udp.h"
                     42: #include "includes/netinet/if_ether.h"
                     43: #include <net/if.h>
                     44: 
                     45: /* Reinitializes the specified interface after an address change.   This
                     46:    is not required for packet-filter APIs. */
                     47: 
                     48: #ifdef USE_LPF_SEND
                     49: void if_reinitialize_send (info)
                     50:        struct interface_info *info;
                     51: {
                     52: }
                     53: #endif
                     54: 
                     55: #ifdef USE_LPF_RECEIVE
                     56: void if_reinitialize_receive (info)
                     57:        struct interface_info *info;
                     58: {
                     59: }
                     60: #endif
                     61: 
                     62: /* Called by get_interface_list for each interface that's discovered.
                     63:    Opens a packet filter for each interface and adds it to the select
                     64:    mask. */
                     65: 
                     66: int if_register_lpf (info)
                     67:        struct interface_info *info;
                     68: {
                     69:        int sock;
                     70:        struct sockaddr sa;
                     71: 
                     72:        /* Make an LPF socket. */
                     73:        if ((sock = socket(PF_PACKET, SOCK_PACKET,
                     74:                           htons((short)ETH_P_ALL))) < 0) {
                     75:                if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
                     76:                    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
                     77:                    errno == EAFNOSUPPORT || errno == EINVAL) {
                     78:                        log_error ("socket: %m - make sure");
                     79:                        log_error ("CONFIG_PACKET (Packet socket) %s",
                     80:                                   "and CONFIG_FILTER");
                     81:                        log_error ("(Socket Filtering) are enabled %s",
                     82:                                   "in your kernel");
                     83:                        log_fatal ("configuration!");
                     84:                }
                     85:                log_fatal ("Open a socket for LPF: %m");
                     86:        }
                     87: 
                     88:        /* Bind to the interface name */
                     89:        memset (&sa, 0, sizeof sa);
                     90:        sa.sa_family = AF_PACKET;
                     91:        strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
                     92:        if (bind (sock, &sa, sizeof sa)) {
                     93:                if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
                     94:                    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
                     95:                    errno == EAFNOSUPPORT || errno == EINVAL) {
                     96:                        log_error ("socket: %m - make sure");
                     97:                        log_error ("CONFIG_PACKET (Packet socket) %s",
                     98:                                   "and CONFIG_FILTER");
                     99:                        log_error ("(Socket Filtering) are enabled %s",
                    100:                                   "in your kernel");
                    101:                        log_fatal ("configuration!");
                    102:                }
                    103:                log_fatal ("Bind socket to interface: %m");
                    104:        }
                    105: 
                    106:        get_hw_addr(info->name, &info->hw_address);
                    107: 
                    108:        return sock;
                    109: }
                    110: #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
                    111: 
                    112: #ifdef USE_LPF_SEND
                    113: void if_register_send (info)
                    114:        struct interface_info *info;
                    115: {
                    116:        /* If we're using the lpf API for sending and receiving,
                    117:           we don't need to register this interface twice. */
                    118: #ifndef USE_LPF_RECEIVE
                    119:        info -> wfdesc = if_register_lpf (info);
                    120: #else
                    121:        info -> wfdesc = info -> rfdesc;
                    122: #endif
                    123:        if (!quiet_interface_discovery)
                    124:                log_info ("Sending on   LPF/%s/%s%s%s",
                    125:                      info -> name,
                    126:                      print_hw_addr (info -> hw_address.hbuf [0],
                    127:                                     info -> hw_address.hlen - 1,
                    128:                                     &info -> hw_address.hbuf [1]),
                    129:                      (info -> shared_network ? "/" : ""),
                    130:                      (info -> shared_network ?
                    131:                       info -> shared_network -> name : ""));
                    132: }
                    133: 
                    134: void if_deregister_send (info)
                    135:        struct interface_info *info;
                    136: {
                    137:        /* don't need to close twice if we are using lpf for sending and
                    138:           receiving */
                    139: #ifndef USE_LPF_RECEIVE
                    140:        /* for LPF this is simple, packet filters are removed when sockets
                    141:           are closed */
                    142:        close (info -> wfdesc);
                    143: #endif
                    144:        info -> wfdesc = -1;
                    145:        if (!quiet_interface_discovery)
                    146:                log_info ("Disabling output on LPF/%s/%s%s%s",
                    147:                      info -> name,
                    148:                      print_hw_addr (info -> hw_address.hbuf [0],
                    149:                                     info -> hw_address.hlen - 1,
                    150:                                     &info -> hw_address.hbuf [1]),
                    151:                      (info -> shared_network ? "/" : ""),
                    152:                      (info -> shared_network ?
                    153:                       info -> shared_network -> name : ""));
                    154: }
                    155: #endif /* USE_LPF_SEND */
                    156: 
                    157: #ifdef USE_LPF_RECEIVE
                    158: /* Defined in bpf.c.   We can't extern these in dhcpd.h without pulling
                    159:    in bpf includes... */
                    160: extern struct sock_filter dhcp_bpf_filter [];
                    161: extern int dhcp_bpf_filter_len;
                    162: 
                    163: #if defined (HAVE_TR_SUPPORT)
                    164: extern struct sock_filter dhcp_bpf_tr_filter [];
                    165: extern int dhcp_bpf_tr_filter_len;
                    166: static void lpf_tr_filter_setup (struct interface_info *);
                    167: #endif
                    168: 
                    169: static void lpf_gen_filter_setup (struct interface_info *);
                    170: 
                    171: void if_register_receive (info)
                    172:        struct interface_info *info;
                    173: {
                    174:        /* Open a LPF device and hang it on this interface... */
                    175:        info -> rfdesc = if_register_lpf (info);
                    176: 
                    177: #if defined (HAVE_TR_SUPPORT)
                    178:        if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
                    179:                lpf_tr_filter_setup (info);
                    180:        else
                    181: #endif
                    182:                lpf_gen_filter_setup (info);
                    183: 
                    184:        if (!quiet_interface_discovery)
                    185:                log_info ("Listening on LPF/%s/%s%s%s",
                    186:                          info -> name,
                    187:                          print_hw_addr (info -> hw_address.hbuf [0],
                    188:                                         info -> hw_address.hlen - 1,
                    189:                                         &info -> hw_address.hbuf [1]),
                    190:                          (info -> shared_network ? "/" : ""),
                    191:                          (info -> shared_network ?
                    192:                           info -> shared_network -> name : ""));
                    193: }
                    194: 
                    195: void if_deregister_receive (info)
                    196:        struct interface_info *info;
                    197: {
                    198:        /* for LPF this is simple, packet filters are removed when sockets
                    199:           are closed */
                    200:        close (info -> rfdesc);
                    201:        info -> rfdesc = -1;
                    202:        if (!quiet_interface_discovery)
                    203:                log_info ("Disabling input on LPF/%s/%s%s%s",
                    204:                          info -> name,
                    205:                          print_hw_addr (info -> hw_address.hbuf [0],
                    206:                                         info -> hw_address.hlen - 1,
                    207:                                         &info -> hw_address.hbuf [1]),
                    208:                          (info -> shared_network ? "/" : ""),
                    209:                          (info -> shared_network ?
                    210:                           info -> shared_network -> name : ""));
                    211: }
                    212: 
                    213: static void lpf_gen_filter_setup (info)
                    214:        struct interface_info *info;
                    215: {
                    216:        struct sock_fprog p;
                    217: 
                    218:        memset(&p, 0, sizeof(p));
                    219: 
                    220:        /* Set up the bpf filter program structure.    This is defined in
                    221:           bpf.c */
                    222:        p.len = dhcp_bpf_filter_len;
                    223:        p.filter = dhcp_bpf_filter;
                    224: 
                    225:         /* Patch the server port into the LPF  program...
                    226:           XXX changes to filter program may require changes
                    227:           to the insn number(s) used below! XXX */
                    228:        dhcp_bpf_filter [8].k = ntohs ((short)local_port);
                    229: 
                    230:        if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
                    231:                        sizeof p) < 0) {
                    232:                if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
                    233:                    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
                    234:                    errno == EAFNOSUPPORT) {
                    235:                        log_error ("socket: %m - make sure");
                    236:                        log_error ("CONFIG_PACKET (Packet socket) %s",
                    237:                                   "and CONFIG_FILTER");
                    238:                        log_error ("(Socket Filtering) are enabled %s",
                    239:                                   "in your kernel");
                    240:                        log_fatal ("configuration!");
                    241:                }
                    242:                log_fatal ("Can't install packet filter program: %m");
                    243:        }
                    244: }
                    245: 
                    246: #if defined (HAVE_TR_SUPPORT)
                    247: static void lpf_tr_filter_setup (info)
                    248:        struct interface_info *info;
                    249: {
                    250:        struct sock_fprog p;
                    251: 
                    252:        memset(&p, 0, sizeof(p));
                    253: 
                    254:        /* Set up the bpf filter program structure.    This is defined in
                    255:           bpf.c */
                    256:        p.len = dhcp_bpf_tr_filter_len;
                    257:        p.filter = dhcp_bpf_tr_filter;
                    258: 
                    259:         /* Patch the server port into the LPF  program...
                    260:           XXX changes to filter program may require changes
                    261:           XXX to the insn number(s) used below!
                    262:           XXX Token ring filter is null - when/if we have a filter 
                    263:           XXX that's not, we'll need this code.
                    264:           XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
                    265: 
                    266:        if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
                    267:                        sizeof p) < 0) {
                    268:                if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
                    269:                    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
                    270:                    errno == EAFNOSUPPORT) {
                    271:                        log_error ("socket: %m - make sure");
                    272:                        log_error ("CONFIG_PACKET (Packet socket) %s",
                    273:                                   "and CONFIG_FILTER");
                    274:                        log_error ("(Socket Filtering) are enabled %s",
                    275:                                   "in your kernel");
                    276:                        log_fatal ("configuration!");
                    277:                }
                    278:                log_fatal ("Can't install packet filter program: %m");
                    279:        }
                    280: }
                    281: #endif /* HAVE_TR_SUPPORT */
                    282: #endif /* USE_LPF_RECEIVE */
                    283: 
                    284: #ifdef USE_LPF_SEND
                    285: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
                    286:        struct interface_info *interface;
                    287:        struct packet *packet;
                    288:        struct dhcp_packet *raw;
                    289:        size_t len;
                    290:        struct in_addr from;
                    291:        struct sockaddr_in *to;
                    292:        struct hardware *hto;
                    293: {
                    294:        unsigned hbufp = 0, ibufp = 0;
                    295:        double hh [16];
                    296:        double ih [1536 / sizeof (double)];
                    297:        unsigned char *buf = (unsigned char *)ih;
                    298:        struct sockaddr_pkt sa;
                    299:        int result;
                    300:        int fudge;
                    301: 
                    302:        if (!strcmp (interface -> name, "fallback"))
                    303:                return send_fallback (interface, packet, raw,
                    304:                                      len, from, to, hto);
                    305: 
                    306:        /* Assemble the headers... */
                    307:        assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
                    308:        fudge = hbufp % 4;      /* IP header must be word-aligned. */
                    309:        memcpy (buf + fudge, (unsigned char *)hh, hbufp);
                    310:        ibufp = hbufp + fudge;
                    311:        assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
                    312:                                to -> sin_addr.s_addr, to -> sin_port,
                    313:                                (unsigned char *)raw, len);
                    314:        memcpy (buf + ibufp, raw, len);
                    315: 
                    316:        /* For some reason, SOCK_PACKET sockets can't be connected,
                    317:           so we have to do a sentdo every time. */
                    318:        memset (&sa, 0, sizeof sa);
                    319:        sa.spkt_family = AF_PACKET;
                    320:        strncpy ((char *)sa.spkt_device,
                    321:                 (const char *)interface -> ifp, sizeof sa.spkt_device);
                    322:        sa.spkt_protocol = htons(ETH_P_IP);
                    323: 
                    324:        result = sendto (interface -> wfdesc,
                    325:                         buf + fudge, ibufp + len - fudge, 0, 
                    326:                         (const struct sockaddr *)&sa, sizeof sa);
                    327:        if (result < 0)
                    328:                log_error ("send_packet: %m");
                    329:        return result;
                    330: }
                    331: #endif /* USE_LPF_SEND */
                    332: 
                    333: #ifdef USE_LPF_RECEIVE
                    334: ssize_t receive_packet (interface, buf, len, from, hfrom)
                    335:        struct interface_info *interface;
                    336:        unsigned char *buf;
                    337:        size_t len;
                    338:        struct sockaddr_in *from;
                    339:        struct hardware *hfrom;
                    340: {
                    341:        int length = 0;
                    342:        int offset = 0;
                    343:        unsigned char ibuf [1536];
                    344:        unsigned bufix = 0;
                    345:        unsigned paylen;
                    346: 
                    347:        length = read (interface -> rfdesc, ibuf, sizeof ibuf);
                    348:        if (length <= 0)
                    349:                return length;
                    350: 
                    351:        bufix = 0;
                    352:        /* Decode the physical header... */
                    353:        offset = decode_hw_header (interface, ibuf, bufix, hfrom);
                    354: 
                    355:        /* If a physical layer checksum failed (dunno of any
                    356:           physical layer that supports this, but WTH), skip this
                    357:           packet. */
                    358:        if (offset < 0) {
                    359:                return 0;
                    360:        }
                    361: 
                    362:        bufix += offset;
                    363:        length -= offset;
                    364: 
                    365:        /* Decode the IP and UDP headers... */
                    366:        offset = decode_udp_ip_header (interface, ibuf, bufix, from,
                    367:                                       (unsigned)length, &paylen);
                    368: 
                    369:        /* If the IP or UDP checksum was bad, skip the packet... */
                    370:        if (offset < 0)
                    371:                return 0;
                    372: 
                    373:        bufix += offset;
                    374:        length -= offset;
                    375: 
                    376:        if (length < paylen)
                    377:                log_fatal("Internal inconsistency at %s:%d.", MDL);
                    378: 
                    379:        /* Copy out the data in the packet... */
                    380:        memcpy(buf, &ibuf[bufix], paylen);
                    381:        return paylen;
                    382: }
                    383: 
                    384: int can_unicast_without_arp (ip)
                    385:        struct interface_info *ip;
                    386: {
                    387:        return 1;
                    388: }
                    389: 
                    390: int can_receive_unicast_unconfigured (ip)
                    391:        struct interface_info *ip;
                    392: {
                    393:        return 1;
                    394: }
                    395: 
                    396: int supports_multiple_interfaces (ip)
                    397:        struct interface_info *ip;
                    398: {
                    399:        return 1;
                    400: }
                    401: 
                    402: void maybe_setup_fallback ()
                    403: {
                    404:        isc_result_t status;
                    405:        struct interface_info *fbi = (struct interface_info *)0;
                    406:        if (setup_fallback (&fbi, MDL)) {
                    407:                if_register_fallback (fbi);
                    408:                status = omapi_register_io_object ((omapi_object_t *)fbi,
                    409:                                                   if_readsocket, 0,
                    410:                                                   fallback_discard, 0, 0);
                    411:                if (status != ISC_R_SUCCESS)
                    412:                        log_fatal ("Can't register I/O handle for \"%s\": %s",
                    413:                                   fbi -> name, isc_result_totext (status));
                    414:                interface_dereference (&fbi, MDL);
                    415:        }
                    416: }
                    417: 
                    418: void
                    419: get_hw_addr(const char *name, struct hardware *hw) {
                    420:        int sock;
                    421:        struct ifreq tmp;
                    422:        struct sockaddr *sa;
                    423: 
                    424:        if (strlen(name) >= sizeof(tmp.ifr_name)) {
                    425:                log_fatal("Device name too long: \"%s\"", name);
                    426:        }
                    427: 
                    428:        sock = socket(AF_INET, SOCK_DGRAM, 0);
                    429:        if (sock < 0) {
                    430:                log_fatal("Can't create socket for \"%s\": %m", name);
                    431:        }
                    432: 
                    433:        memset(&tmp, 0, sizeof(tmp));
                    434:        strcpy(tmp.ifr_name, name);
                    435:        if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
                    436:                log_fatal("Error getting hardware address for \"%s\": %m", 
                    437:                          name);
                    438:        }
                    439: 
                    440:        sa = &tmp.ifr_hwaddr;
                    441:        switch (sa->sa_family) {
                    442:                case ARPHRD_ETHER:
                    443:                        hw->hlen = 7;
                    444:                        hw->hbuf[0] = HTYPE_ETHER;
                    445:                        memcpy(&hw->hbuf[1], sa->sa_data, 6);
                    446:                        break;
                    447:                case ARPHRD_IEEE802:
                    448: #ifdef ARPHRD_IEEE802_TR
                    449:                case ARPHRD_IEEE802_TR:
                    450: #endif /* ARPHRD_IEEE802_TR */
                    451:                        hw->hlen = 7;
                    452:                        hw->hbuf[0] = HTYPE_IEEE802;
                    453:                        memcpy(&hw->hbuf[1], sa->sa_data, 6);
                    454:                        break;
                    455:                case ARPHRD_FDDI:
                    456:                        hw->hlen = 17;
                    457:                        hw->hbuf[0] = HTYPE_FDDI;
                    458:                        memcpy(&hw->hbuf[1], sa->sa_data, 16);
                    459:                        break;
                    460:                default:
                    461:                        log_fatal("Unsupported device type %ld for \"%s\"",
                    462:                                  (long int)sa->sa_family, name);
                    463:        }
                    464: 
                    465:        close(sock);
                    466: }
                    467: #endif

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