common/upf.c

Go to the documentation of this file.
00001 /* upf.c
00002 
00003    Ultrix PacketFilter interface code. */
00004 
00005 /*
00006  * Copyright (c) 2004,2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 1996-2003 by Internet Software Consortium
00008  *
00009  * Permission to use, copy, modify, and distribute this software for any
00010  * purpose with or without fee is hereby granted, provided that the above
00011  * copyright notice and this permission notice appear in all copies.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00014  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00015  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00016  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00017  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00018  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00019  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00020  *
00021  *   Internet Systems Consortium, Inc.
00022  *   950 Charter Street
00023  *   Redwood City, CA 94063
00024  *   <info@isc.org>
00025  *   https://www.isc.org/
00026  *
00027  */
00028 
00029 #include "dhcpd.h"
00030 #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
00031 #include <sys/ioctl.h>
00032 #include <sys/uio.h>
00033 
00034 #include <net/pfilt.h>
00035 #include <netinet/in_systm.h>
00036 #include "includes/netinet/ip.h"
00037 #include "includes/netinet/udp.h"
00038 #include "includes/netinet/if_ether.h"
00039 
00040 /* Reinitializes the specified interface after an address change.   This
00041    is not required for packet-filter APIs. */
00042 
00043 #ifdef USE_UPF_SEND
00044 void if_reinitialize_send (info)
00045         struct interface_info *info;
00046 {
00047 }
00048 #endif
00049 
00050 #ifdef USE_UPF_RECEIVE
00051 void if_reinitialize_receive (info)
00052         struct interface_info *info;
00053 {
00054 }
00055 #endif
00056 
00057 /* Called by get_interface_list for each interface that's discovered.
00058    Opens a packet filter for each interface and adds it to the select
00059    mask. */
00060 
00061 int if_register_upf (info)
00062         struct interface_info *info;
00063 {
00064         int sock;
00065         char filename[50];
00066         int b;
00067         struct endevp param;
00068 
00069         /* Open a UPF device */
00070         for (b = 0; 1; b++) {
00071                 /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
00072                 sprintf(filename, "/dev/pf/pfilt%d", b);
00073 
00074                 sock = open (filename, O_RDWR | O_CLOEXEC, 0);
00075                 if (sock < 0) {
00076                         if (errno == EBUSY) {
00077                                 continue;
00078                         } else {
00079                                 log_fatal ("Can't find free upf: %m");
00080                         }
00081                 } else {
00082                         break;
00083                 }
00084         }
00085 
00086         /* Set the UPF device to point at this interface. */
00087         if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
00088                 log_fatal ("Can't attach interface %s to upf device %s: %m",
00089                        info -> name, filename);
00090 
00091         /* Get the hardware address. */
00092         if (ioctl (sock, EIOCDEVP, &param) < 0)
00093                 log_fatal ("Can't get interface %s hardware address: %m",
00094                        info -> name);
00095 
00096         /* We only know how to do ethernet. */
00097         if (param.end_dev_type != ENDT_10MB)    
00098                 log_fatal ("Invalid device type on network interface %s: %d",
00099                        info -> name, param.end_dev_type);
00100 
00101         if (param.end_addr_len != 6)
00102                 log_fatal ("Invalid hardware address length on %s: %d",
00103                        info -> name, param.end_addr_len);
00104 
00105         info -> hw_address.hlen = 7;
00106         info -> hw_address.hbuf [0] = ARPHRD_ETHER;
00107         memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6);
00108 
00109         return sock;
00110 }
00111 #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
00112 
00113 #ifdef USE_UPF_SEND
00114 void if_register_send (info)
00115         struct interface_info *info;
00116 {
00117         /* If we're using the upf API for sending and receiving,
00118            we don't need to register this interface twice. */
00119 #ifndef USE_UPF_RECEIVE
00120         info -> wfdesc = if_register_upf (info, interface);
00121 #else
00122         info -> wfdesc = info -> rfdesc;
00123 #endif
00124         if (!quiet_interface_discovery)
00125                 log_info ("Sending on   UPF/%s/%s%s%s",
00126                       info -> name,
00127                       print_hw_addr (info -> hw_address.hbuf [0],
00128                                      info -> hw_address.hlen - 1,
00129                                      &info -> hw_address.hbuf [1]),
00130                       (info -> shared_network ? "/" : ""),
00131                       (info -> shared_network ?
00132                        info -> shared_network -> name : ""));
00133 }
00134 
00135 void if_deregister_send (info)
00136         struct interface_info *info;
00137 {
00138 #ifndef USE_UPF_RECEIVE
00139         close (info -> wfdesc);
00140 #endif
00141         info -> wfdesc = -1;
00142         if (!quiet_interface_discovery)
00143                 log_info ("Disabling output on UPF/%s/%s%s%s",
00144                       info -> name,
00145                       print_hw_addr (info -> hw_address.hbuf [0],
00146                                      info -> hw_address.hlen - 1,
00147                                      &info -> hw_address.hbuf [1]),
00148                       (info -> shared_network ? "/" : ""),
00149                       (info -> shared_network ?
00150                        info -> shared_network -> name : ""));
00151 }
00152 #endif /* USE_UPF_SEND */
00153 
00154 #ifdef USE_UPF_RECEIVE
00155 /* Packet filter program...
00156    XXX Changes to the filter program may require changes to the constant
00157    offsets used in if_register_send to patch the UPF program! XXX */
00158 
00159 
00160 void if_register_receive (info)
00161         struct interface_info *info;
00162 {
00163         int flag = 1;
00164         u_int32_t addr;
00165         struct enfilter pf;
00166         u_int32_t bits;
00167 
00168         /* Open a UPF device and hang it on this interface... */
00169         info -> rfdesc = if_register_upf (info);
00170 
00171         /* Allow the copyall flag to be set... */
00172         if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
00173                 log_fatal ("Can't set ALLOWCOPYALL: %m");
00174 
00175         /* Clear all the packet filter mode bits first... */
00176         flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
00177                 ENNONEXCL | ENCOPYALL);
00178         if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
00179                 log_fatal ("Can't clear pfilt bits: %m");
00180 
00181         /* Set the ENBATCH and ENCOPYALL bits... */
00182         bits = ENBATCH | ENCOPYALL;
00183         if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
00184                 log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
00185 
00186         /* Set up the UPF filter program. */
00187         /* XXX Unlike the BPF filter program, this one won't work if the
00188            XXX IP packet is fragmented or if there are options on the IP
00189            XXX header. */
00190         pf.enf_Priority = 0;
00191         pf.enf_FilterLen = 0;
00192 
00193         pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
00194         pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
00195         pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
00196         pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
00197         pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
00198         pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
00199         pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
00200         pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
00201         pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
00202         pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
00203         pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
00204         pf.enf_Filter [pf.enf_FilterLen++] = local_port;
00205 
00206         if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
00207                 log_fatal ("Can't install packet filter program: %m");
00208         if (!quiet_interface_discovery)
00209                 log_info ("Listening on UPF/%s/%s%s%s",
00210                       info -> name,
00211                       print_hw_addr (info -> hw_address.hbuf [0],
00212                                      info -> hw_address.hlen - 1,
00213                                      &info -> hw_address.hbuf [1]),
00214                       (info -> shared_network ? "/" : ""),
00215                       (info -> shared_network ?
00216                        info -> shared_network -> name : ""));
00217 }
00218 
00219 void if_deregister_receive (info)
00220         struct interface_info *info;
00221 {
00222         close (info -> rfdesc);
00223         info -> rfdesc = -1;
00224         if (!quiet_interface_discovery)
00225                 log_info ("Disabling input on UPF/%s/%s%s%s",
00226                       info -> name,
00227                       print_hw_addr (info -> hw_address.hbuf [0],
00228                                      info -> hw_address.hlen - 1,
00229                                      &info -> hw_address.hbuf [1]),
00230                       (info -> shared_network ? "/" : ""),
00231                       (info -> shared_network ?
00232                        info -> shared_network -> name : ""));
00233 }
00234 #endif /* USE_UPF_RECEIVE */
00235 
00236 #ifdef USE_UPF_SEND
00237 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
00238         struct interface_info *interface;
00239         struct packet *packet;
00240         struct dhcp_packet *raw;
00241         size_t len;
00242         struct in_addr from;
00243         struct sockaddr_in *to;
00244         struct hardware *hto;
00245 {
00246         unsigned hbufp = 0, ibufp = 0;
00247         double hw [4];
00248         double ip [32];
00249         struct iovec iov [3];
00250         int result;
00251         int fudge;
00252 
00253         if (!strcmp (interface -> name, "fallback"))
00254                 return send_fallback (interface, packet, raw,
00255                                       len, from, to, hto);
00256 
00257         if (hto == NULL && interface->anycast_mac_addr.hlen)
00258                 hto = &interface->anycast_mac_addr;
00259 
00260         /* Assemble the headers... */
00261         assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
00262         assemble_udp_ip_header (interface,
00263                                 (unsigned char *)ip, &ibufp, from.s_addr,
00264                                 to -> sin_addr.s_addr, to -> sin_port,
00265                                 (unsigned char *)raw, len);
00266 
00267         /* Fire it off */
00268         iov [0].iov_base = ((char *)hw);
00269         iov [0].iov_len = hbufp;
00270         iov [1].iov_base = ((char *)ip);
00271         iov [1].iov_len = ibufp;
00272         iov [2].iov_base = (char *)raw;
00273         iov [2].iov_len = len;
00274 
00275         result = writev(interface -> wfdesc, iov, 3);
00276         if (result < 0)
00277                 log_error ("send_packet: %m");
00278         return result;
00279 }
00280 #endif /* USE_UPF_SEND */
00281 
00282 #ifdef USE_UPF_RECEIVE
00283 ssize_t receive_packet (interface, buf, len, from, hfrom)
00284         struct interface_info *interface;
00285         unsigned char *buf;
00286         size_t len;
00287         struct sockaddr_in *from;
00288         struct hardware *hfrom;
00289 {
00290         int nread;
00291         int length = 0;
00292         int offset = 0;
00293         unsigned char ibuf [1500 + sizeof (struct enstamp)];
00294         int bufix = 0;
00295         unsigned paylen;
00296 
00297         length = read (interface -> rfdesc, ibuf, sizeof ibuf);
00298         if (length <= 0)
00299                 return length;
00300 
00301         bufix = sizeof (struct enstamp);
00302         /* Decode the physical header... */
00303         offset = decode_hw_header (interface, ibuf, bufix, hfrom);
00304 
00305         /* If a physical layer checksum failed (dunno of any
00306            physical layer that supports this, but WTH), skip this
00307            packet. */
00308         if (offset < 0) {
00309                 return 0;
00310         }
00311 
00312         bufix += offset;
00313         length -= offset;
00314 
00315         /* Decode the IP and UDP headers... */
00316         offset = decode_udp_ip_header (interface, ibuf, bufix,
00317                                        from, length, &paylen, 0);
00318 
00319         /* If the IP or UDP checksum was bad, skip the packet... */
00320         if (offset < 0)
00321                 return 0;
00322 
00323         bufix += offset;
00324         length -= offset;
00325 
00326         if (length < paylen)
00327                 log_fatal("Internal inconsistency at %s:%d.", MDL);
00328 
00329         /* Copy out the data in the packet... */
00330         memcpy (buf, &ibuf[bufix], paylen);
00331         return paylen;
00332 }
00333 
00334 int can_unicast_without_arp (ip)
00335         struct interface_info *ip;
00336 {
00337         return 1;
00338 }
00339 
00340 int can_receive_unicast_unconfigured (ip)
00341         struct interface_info *ip;
00342 {
00343         return 1;
00344 }
00345 
00346 int supports_multiple_interfaces (ip)
00347         struct interface_info *ip;
00348 {
00349         return 1;
00350 }
00351 
00352 void maybe_setup_fallback ()
00353 {
00354         isc_result_t status;
00355         struct interface_info *fbi = (struct interface_info *)0;
00356         if (setup_fallback (&fbi, MDL)) {
00357                 if_register_fallback (fbi);
00358                 status = omapi_register_io_object ((omapi_object_t *)fbi,
00359                                                    if_readsocket, 0,
00360                                                    fallback_discard, 0, 0);
00361                 if (status != ISC_R_SUCCESS)
00362                         log_fatal ("Can't register I/O handle for %s: %s",
00363                                    fbi -> name, isc_result_totext (status));
00364                 interface_dereference (&fbi, MDL);
00365         }
00366 }
00367 #endif

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1