root/trunk/src/common/sendpacket.c

Revision 2066, 26.2 kB (checked in by aturner, 11 days ago)

fix compile issue. fixes #326

  • Property svn:keywords set to Id HeadURL Author Rev Date
Line 
1/* $Id$ */
2
3/*
4 * Copyright (c) 2006 Aaron Turner.
5 * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
6 * Copyright (c) 2000 Torsten Landschoff <torsten@debian.org>
7 *                    Sebastian Krahmer  <krahmer@cs.uni-potsdam.de>
8 * Copyright (c) 1993, 1994, 1995, 1996, 1998
9 *      The Regents of the University of California.
10 * All rights reserved.
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 *
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. Neither the names of the copyright owners nor the names of its
22 *    contributors may be used to endorse or promote products derived from
23 *    this software without specific prior written permission.
24 * 4. All advertising materials mentioning features or use of this software
25 *    display the following acknowledgement:
26 *    ``This product includes software developed by the University of
27 *    California,  Lawrence Berkeley Laboratory and its contributors.''
28 *
29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
30 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
32 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
33 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
35 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
37 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
38 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
39 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41 
42 /* sendpacket.[ch] is my attempt to write a universal packet injection
43  * API for BPF, libpcap, libdnet, and Linux's PF_PACKET.  I got sick
44  * and tired dealing with libnet bugs and its lack of active maintenence,
45  * but unfortunately, libpcap frame injection support is relatively new
46  * and not everyone uses Linux, so I decided to support all four as
47  * best as possible.  If your platform/OS/hardware supports an additional
48  * injection method, then by all means add it here (and send me a patch).
49  *
50  * Anyways, long story short, for now the order of preference is:
51  * 1. PF_PACKET
52  * 2. BPF
53  * 3. libdnet
54  * 4. pcap_inject()
55  * 5. pcap_sendpacket()
56  *
57  * Right now, one big problem with the pcap_* methods is that libpcap
58  * doesn't provide a reliable method of getting the MAC address of
59  * an interface (required for tcpbridge). 
60  * You can use PF_PACKET or BPF to get that, but if your system suports
61  * those, might as well inject directly without going through another
62  * level of indirection.
63  *
64  * Please note that some of this code was copied from Libnet 1.1.3
65  */
66
67#include "config.h"
68#include "defines.h"
69#include "common.h"
70#include "sendpacket.h"
71
72
73#ifdef FORCE_INJECT_LIBDNET
74#undef HAVE_PF_PACKET
75#undef HAVE_PCAP_INJECT
76#undef HAVE_PCAP_SENDPACKET
77#undef HAVE_BPF
78#endif
79
80#ifdef FORCE_INJECT_BPF
81#undef HAVE_LIBDNET
82#undef HAVE_PCAP_INJECT
83#undef HAVE_PCAP_SENDPACKET
84#undef HAVE_PF_PACKET
85#endif
86
87#ifdef FORCE_INJECT_PCAP_INJECT
88#undef HAVE_LIBDNET
89#undef HAVE_PCAP_SENDPACKET
90#undef HAVE_BPF
91#undef HAVE_PF_PACKET
92#endif
93
94#ifdef FORCE_INJECT_PCAP_SENDPACKET
95#undef HAVE_LIBDNET
96#undef HAVE_PCAP_INJECT
97#undef HAVE_BPF
98#undef HAVE_PF_PACKET
99#endif
100
101#if (defined HAVE_WINPCAP && defined HAVE_PCAP_INJECT)
102#undef HAVE_PCAP_INJECT /* configure returns true for some odd reason */
103#endif
104
105#if !defined HAVE_PCAP_INJECT && !defined HAVE_PCAP_SENDPACKET && !defined HAVE_LIBDNET && !defined HAVE_PF_PACKET && !defined HAVE_BPF
106#error You need pcap_inject() or pcap_sendpacket() from libpcap, libdnet, Linux's PF_PACKET or *BSD's BPF
107#endif
108
109#include <string.h>
110#include <errno.h>
111#include <stdarg.h>
112#include <stdio.h>
113#include <sys/types.h>
114#include <sys/time.h>
115#include <sys/ioctl.h>
116#include <sys/file.h>
117#include <sys/socket.h>
118#ifdef HAVE_SYS_PARAM_H
119#include <sys/param.h>
120#endif
121#ifdef HAVE_SYS_SYSCTL_H
122#include <sys/sysctl.h>
123#endif
124#ifdef HAVE_NET_ROUTE_H
125#include <net/route.h>
126#endif
127#include <stdlib.h>
128#include <unistd.h>
129
130#ifdef HAVE_PF_PACKET
131#undef INJECT_METHOD
132#define INJECT_METHOD "PF_PACKET send()"
133
134#include <fcntl.h>
135#include <sys/utsname.h>
136#include <net/if.h>
137#include <netinet/in.h>
138#include <linux/if_ether.h>
139#include <net/if_arp.h>
140#include <netpacket/packet.h>
141
142#ifndef __GLIBC__
143typedef int socklen_t;
144#endif
145
146static sendpacket_t *sendpacket_open_pf(const char *, char *);
147static struct tcpr_ether_addr *sendpacket_get_hwaddr_pf(sendpacket_t *);
148static int get_iface_index(int fd, const int8_t *device, char *);
149
150#endif /* HAVE_PF_PACKET */
151
152#ifdef HAVE_BPF
153#undef INJECT_METHOD
154#define INJECT_METHOD "bpf send()"
155
156#include <net/bpf.h>
157#include <sys/socket.h>
158#include <net/if.h>
159#include <sys/uio.h>
160#include <net/if_dl.h> // used for get_hwaddr_bpf()
161
162static sendpacket_t *sendpacket_open_bpf(const char *, char *) _U_;
163static struct tcpr_ether_addr *sendpacket_get_hwaddr_bpf(sendpacket_t *) _U_;
164
165#endif /* HAVE_BPF */
166
167#ifdef HAVE_LIBDNET
168#undef INJECT_METHOD
169#define INJECT_METHOD "libdnet eth_send()"
170/* need to undef these which are pulled in via defines.h, prior to importing dnet.h */
171#undef icmp_id
172#undef icmp_seq
173#undef icmp_data
174#undef icmp_mask
175#include <dnet.h>
176
177static sendpacket_t *sendpacket_open_libdnet(const char *, char *) _U_;
178static struct tcpr_ether_addr *sendpacket_get_hwaddr_libdnet(sendpacket_t *) _U_;
179#endif /* HAVE_LIBDNET */
180
181#if (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET)
182static sendpacket_t *sendpacket_open_pcap(const char *, char *) _U_;
183static struct tcpr_ether_addr *sendpacket_get_hwaddr_pcap(sendpacket_t *) _U_;
184#endif /* HAVE_PCAP_INJECT || HAVE_PACKET_SENDPACKET */
185
186#ifdef HAVE_PCAP_INJECT
187#undef INJECT_METHOD
188#define INJECT_METHOD "pcap_inject()"
189#elif defined HAVE_PCAP_SENDPACKET
190#undef INJECT_METHOD
191#define INJECT_METHOD "pcap_sendpacket()"
192#endif
193
194static void sendpacket_seterr(sendpacket_t *sp, const char *fmt, ...);
195
196/* You need to define didsig in your main .c file.  Set to 1 if CTRL-C was pressed */
197extern volatile int didsig;
198
199
200/**
201 * returns number of bytes sent on success or -1 on error
202 * Note: it is theoretically possible to get a return code >0 and < len
203 * which for most people would be considered an error (the packet wasn't fully sent)
204 * so you may want to test for recode != len too.
205 *
206 * Most socket API's have two interesting errors: ENOBUFS & EAGAIN.  ENOBUFS
207 * is usually due to the kernel buffers being full.  EAGAIN happens when you
208 * try to send traffic faster then the PHY allows.
209 */
210int
211sendpacket(sendpacket_t *sp, const u_char *data, size_t len)
212{
213    int retcode;
214
215    assert(sp);
216    assert(data);
217       
218    if (len <= 0)
219        return -1;
220               
221TRY_SEND_AGAIN:
222    sp->attempt ++;
223
224#if defined HAVE_PF_PACKET
225    retcode = (int)send(sp->handle.fd, (void *)data, len, 0);
226
227    /* out of buffers, or hit max PHY speed, silently retry */
228    if (retcode < 0 && !didsig) {
229        switch (errno) {
230            case EAGAIN:
231                sp->retry_eagain ++;
232                goto TRY_SEND_AGAIN;
233                break;
234            case ENOBUFS:
235                sp->retry_enobufs ++;
236                goto TRY_SEND_AGAIN;
237                break;
238               
239            default:
240                sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
241                    INJECT_METHOD, sp->sent + 1, strerror(errno), errno);
242        }
243    } 
244
245#elif defined HAVE_BPF
246    retcode = write(sp->handle.fd, (void *)data, len);
247
248    /* out of buffers, or hit max PHY speed, silently retry */
249    if (retcode < 0 && !didsig) {
250        switch (errno) {
251            case EAGAIN:
252                sp->retry_eagain ++;
253                goto TRY_SEND_AGAIN;
254                break;
255
256            case ENOBUFS:
257                sp->retry_enobufs ++;
258                goto TRY_SEND_AGAIN;
259                break;
260               
261            default:
262                sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
263                    INJECT_METHOD, sp->sent + 1, strerror(errno), errno);
264        }
265    }
266
267#elif defined HAVE_LIBDNET
268    retcode = eth_send(sp->handle.ldnet, (void*)data, (size_t)len);
269
270    /* out of buffers, or hit max PHY speed, silently retry */
271    if (retcode < 0 && !didsig) {
272        switch (errno) {
273            case EAGAIN:
274                sp->retry_eagain ++;
275                goto TRY_SEND_AGAIN;
276                break;
277
278            case ENOBUFS:
279                sp->retry_enobufs ++;
280                goto TRY_SEND_AGAIN;
281                break;
282               
283            default:
284                sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
285                    INJECT_METHOD, sp->sent + 1, strerror(errno), errno);
286        }
287    }
288
289#elif defined HAVE_PCAP_INJECT
290    /*
291     * pcap methods don't seem to support ENOBUFS, so we just straight fail
292     * is there a better way???
293     */   
294    retcode = pcap_inject(sp->handle.pcap, (void*)data, len);
295    /* out of buffers, or hit max PHY speed, silently retry */
296    if (retcode < 0 && !didsig) {
297        switch (errno) {
298            case EAGAIN:
299                sp->retry_eagain ++;
300                goto TRY_SEND_AGAIN;
301                break;
302
303            case ENOBUFS:
304                sp->retry_enobufs ++;
305                goto TRY_SEND_AGAIN;
306                break;
307               
308            default:
309                sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
310                    INJECT_METHOD, sp->sent + 1, pcap_geterr(sp->handle.pcap), errno);
311        }
312    }
313
314#elif defined HAVE_PCAP_SENDPACKET
315    retcode = pcap_sendpacket(sp->handle.pcap, data, (int)len);
316    /* out of buffers, or hit max PHY speed, silently retry */
317    if (retcode < 0 && !didsig) {
318        switch (errno) {
319            case EAGAIN:
320                sp->retry_eagain ++;
321                goto TRY_SEND_AGAIN;
322                break;
323
324            case ENOBUFS:
325                sp->retry_enobufs ++;
326                goto TRY_SEND_AGAIN;
327                break;
328               
329            default:
330                sendpacket_seterr(sp, "Error with %s [" COUNTER_SPEC "]: %s (errno = %d)", 
331                    INJECT_METHOD, sp->sent + 1, pcap_geterr(sp->handle.pcap), errno);
332         }
333    }
334    /*
335     * pcap_sendpacket returns 0 on success, not the packet length!
336     * hence, we have to fix retcode to be more standard on success
337     */
338    if (retcode == 0)
339        retcode = len;
340
341#endif
342
343    if (retcode < 0) {
344        sp->failed ++;
345    } else if (retcode != (int)len) {
346        sendpacket_seterr(sp, "Only able to write %d bytes out of %u bytes total",
347            retcode, len);
348    } else {
349        sp->bytes_sent += len;
350        sp->sent ++;
351    }
352    return retcode;
353}
354
355/**
356 * Open the given network device name and returns a sendpacket_t struct
357 * pass the error buffer (in case there's a problem) and the direction
358 * that this interface represents
359 */
360sendpacket_t *
361sendpacket_open(const char *device, char *errbuf, tcpr_dir_t direction)
362{
363    sendpacket_t *sp;
364
365    assert(device);
366    assert(errbuf);
367
368#if defined HAVE_PF_PACKET
369    sp = sendpacket_open_pf(device, errbuf);
370#elif defined HAVE_BPF
371    sp = sendpacket_open_bpf(device, errbuf);
372#elif defined HAVE_LIBDNET
373    sp = sendpacket_open_libdnet(device, errbuf);
374#elif (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET)
375    sp = sendpacket_open_pcap(device, errbuf);
376#endif
377    if (sp != NULL) {
378        sp->open = 1;
379        sp->cache_dir = direction;
380    }
381    return sp;
382}
383
384/**
385 * Get packet stats for the given sendpacket_t
386 */
387char *
388sendpacket_getstat(sendpacket_t *sp)
389{
390    static char buf[1024];
391   
392    assert(sp);
393   
394    memset(buf, 0, sizeof(buf));
395    sprintf(buf, "Statistics for network device: %s\n"
396        "\tAttempted packets:         " COUNTER_SPEC "\n"
397        "\tSuccessful packets:        " COUNTER_SPEC "\n"
398        "\tFailed packets:            " COUNTER_SPEC "\n"
399        "\tRetried packets (ENOBUFS): " COUNTER_SPEC "\n"
400        "\tRetried packets (EAGAIN):  " COUNTER_SPEC "\n",
401        sp->device, sp->attempt, sp->sent, sp->failed, sp->retry_enobufs, sp->retry_eagain);
402    return(buf);
403}
404
405/**
406 * close the given sendpacket
407 */
408int
409sendpacket_close(sendpacket_t *sp)
410{
411    assert(sp);
412#ifdef HAVE_LIBDNET
413    eth_close(sp->handle.ldnet);
414#elif defined HAVE_LIBPCAP
415    pcap_close(sp->handle.pcap);
416#else
417    close(sp->handle.fd);
418#endif
419    safe_free(sp);
420    return 0;
421}
422
423/**
424 * returns the Layer 2 address of the interface current
425 * open.  on error, return NULL
426 */
427struct tcpr_ether_addr *
428sendpacket_get_hwaddr(sendpacket_t *sp)
429{
430    struct tcpr_ether_addr *addr;   
431    assert(sp);
432   
433    /* if we already have our MAC address stored, just return it */
434    if (memcmp(&sp->ether, "\x00\x00\x00\x00\x00\x00", ETHER_ADDR_LEN) != 0)
435        return &sp->ether;
436       
437#if defined HAVE_PF_PACKET
438    addr = sendpacket_get_hwaddr_pf(sp);
439#elif defined HAVE_BPF
440    addr = sendpacket_get_hwaddr_bpf(sp);
441#elif defined HAVE_LIBDNET
442    addr = sendpacket_get_hwaddr_libdnet(sp);
443#elif (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET)
444    addr = sendpacket_get_hwaddr_pcap(sp);
445#endif
446    return addr;
447}
448
449/**
450 * returns the error string
451 */
452char *
453sendpacket_geterr(sendpacket_t *sp)
454{
455    assert(sp);
456    return sp->errbuf;
457}
458
459/**
460 * Set's the error string
461 */
462static void
463sendpacket_seterr(sendpacket_t *sp, const char *fmt, ...)
464{
465    va_list ap;
466   
467    assert(sp);
468   
469    va_start(ap, fmt);
470    if (fmt != NULL)
471        (void)vsnprintf(sp->errbuf, SENDPACKET_ERRBUF_SIZE, fmt, ap);
472    va_end(ap);
473   
474    sp->errbuf[(SENDPACKET_ERRBUF_SIZE-1)] = '\0'; // be safe
475}
476
477
478#if defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET
479/**
480 * Inner sendpacket_open() method for using libpcap
481 */
482static sendpacket_t *
483sendpacket_open_pcap(const char *device, char *errbuf)
484{
485    pcap_t *pcap;
486    sendpacket_t *sp;
487#ifdef BIOCSHDRCMPLT
488    u_int spoof_eth_src = 1;
489    int fd;
490#endif
491
492    assert(device);
493    assert(errbuf);
494
495    dbg(1, "sendpacket: using Libpcap");
496   
497    /* open_pcap_live automatically fills out our errbuf for us */
498    if ((pcap = pcap_open_live(device, 0, 0, 0, errbuf)) == NULL)
499        return NULL;
500       
501    sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
502    strlcpy(sp->device, device, sizeof(sp->device));
503    sp->handle.pcap = pcap;
504   
505#ifdef BIOCSHDRCMPLT
506    /*
507     * Only systems using BPF on the backend need this...
508     * other systems don't have ioctl and will get compile errors.
509     */
510    fd = pcap_get_selectable_fd(pcap);
511    if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1)
512        errx(1, "Unable to enable source MAC spoof support: %s", strerror(errno));
513#endif
514    return sp;
515}
516
517/**
518 * Get the hardware MAC address for the given interface using libpcap
519 */
520static struct tcpr_ether_addr *
521sendpacket_get_hwaddr_pcap(sendpacket_t *sp)
522{
523    assert(sp);
524    sendpacket_seterr(sp, "Error: sendpacket_get_hwaddr() not yet supported for pcap injection");
525    return NULL;
526}
527#endif /* HAVE_PCAP_INJECT || HAVE_PCAP_SENDPACKET */
528
529#if defined HAVE_LIBNET
530/**
531 * Inner sendpacket_open() method for using libdnet
532 */
533static sendpacket_t * 
534sendpacket_open_libdnet(const char *device, char *errbuf)
535{
536    eth_t *ldnet;
537    sendpacket_t *sp;
538   
539    assert(device);
540    assert(errbuf);
541   
542    dbg(1, "sendpacket: using Libdnet");
543   
544    if ((ldnet = eth_open(device)) == NULL)
545        return NULL;
546
547    sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
548    strlcpy(sp->device, device, sizeof(sp->device));
549    sp->handle.ldnet = ldnet;
550    return sp;   
551}
552
553/**
554 * Get the hardware MAC address for the given interface using libdnet
555 */
556static struct tcpr_ether_addr *
557sendpacket_get_hwaddr_libdnet(sendpacket_t *sp)
558{
559    struct tcpr_ether_addr *addr;
560    int ret;
561    assert(sp);
562   
563    ret = eth_get(sp->handle.ldnet, addr);
564   
565    if (addr == NULL || ret < 0) {
566        sendpacket_seterr(sp, "Error getting hwaddr via libdnet: %s", strerror(errno));
567        return NULL;
568    }
569   
570    memcpy(&sp->ether, addr, sizeof(struct tcpr_ether_addr));
571    return(&sp->ether);
572}
573#endif /* HAVE_LIBDNET */
574
575#if defined HAVE_PF_PACKET
576/**
577 * Inner sendpacket_open() method for using Linux's PF_PACKET
578 */
579static sendpacket_t *
580sendpacket_open_pf(const char *device, char *errbuf)
581{
582    int mysocket;
583    sendpacket_t *sp;
584    struct ifreq ifr;
585    struct sockaddr_ll sa;
586    int n = 1, err;
587    socklen_t errlen = sizeof(err);
588
589    assert(device);
590    assert(errbuf);
591   
592   dbg(1, "sendpacket: using PF_PACKET");
593
594    /* open our socket */
595    if ((mysocket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
596        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "socket: %s", strerror(errno));
597        return NULL;
598    }
599
600   
601    /* get the interface id for the device */
602    if ((sa.sll_ifindex = get_iface_index(mysocket, device, errbuf)) < 0) {
603        close(mysocket);
604        return NULL; 
605    }
606
607    /* bind socket to our interface id */
608    sa.sll_family = AF_PACKET;
609    sa.sll_protocol = htons(ETH_P_ALL);
610    if (bind(mysocket, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
611        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "bind error: %s", strerror(errno));
612        close(mysocket);
613        return NULL;
614    }
615   
616    /* check for errors, network down, etc... */
617    if (getsockopt(mysocket, SOL_SOCKET, SO_ERROR, &err, &errlen) < 0) {
618        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "error opening %s: %s", device, 
619            strerror(errno));
620        close(mysocket);
621        return NULL;
622    }
623   
624    if (err > 0) {
625        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "error opening %s: %s", device, 
626            strerror(err));
627        close(mysocket);
628        return NULL;
629    }
630
631    /* get hardware type for our interface */
632    memset(&ifr, 0, sizeof(ifr));
633    strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
634   
635    if (ioctl(mysocket, SIOCGIFHWADDR, &ifr) < 0) {
636        close(mysocket);
637        sendpacket_seterr(sp, "Error getting hardware type: %s", strerror(errno));
638        return NULL;
639    }
640
641    /* make sure it's not loopback (PF_PACKET doesn't support it) */
642    if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
643        warnx("Unsupported physical layer type 0x%04x on %s.  Maybe it works, maybe it wont."
644        "  See tickets #123/318", ifr.ifr_hwaddr.sa_family, device);
645
646#ifdef SO_BROADCAST
647    /*
648     * man 7 socket
649     *
650     * Set or get the broadcast flag. When  enabled,  datagram  sockets
651     * receive packets sent to a broadcast address and they are allowed
652     * to send packets to a broadcast  address.   This  option  has no
653     * effect on stream-oriented sockets.
654     */ 
655    if (setsockopt(mysocket, SOL_SOCKET, SO_BROADCAST, &n, sizeof(n)) == -1) {
656        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE,
657                "SO_BROADCAST: %s\n", strerror(errno));
658        close(mysocket);
659        return NULL;
660    }
661#endif  /*  SO_BROADCAST  */
662   
663 
664    /* prep & return our sp handle */
665    sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
666    strlcpy(sp->device, device, sizeof(sp->device));
667    sp->handle.fd = mysocket;   
668   
669    return sp;
670}
671
672/**
673 * get the interface index (necessary for sending packets w/ PF_PACKET)
674 */
675static int
676get_iface_index(int fd, const int8_t *device, char *errbuf) {
677    struct ifreq ifr;
678
679    memset(&ifr, 0, sizeof(ifr));
680    strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
681
682    if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) {
683        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "ioctl: %s", strerror(errno));
684        return (-1);
685    }
686
687    return ifr.ifr_ifindex;
688}             
689
690/**
691 * get's the hardware address via Linux's PF packet interface
692 */
693struct tcpr_ether_addr *
694sendpacket_get_hwaddr_pf(sendpacket_t *sp)
695{
696    struct ifreq ifr;
697    int fd;
698   
699    assert(sp);
700   
701    if (!sp->open) {
702        sendpacket_seterr(sp, "Unable to get hardware address on un-opened sendpacket handle");
703        return NULL;
704    }
705   
706
707    /* create dummy socket for ioctl */
708    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
709        sendpacket_seterr(sp, "Unable to open dummy socket for get_hwaddr: %s", strerror(errno));
710        return NULL;
711    }
712
713    memset(&ifr, 0, sizeof(ifr));
714    strlcpy(ifr.ifr_name, sp->device, sizeof(ifr.ifr_name));
715   
716    if (ioctl(fd, SIOCGIFHWADDR, (int8_t *)&ifr) < 0) {
717        close(fd);
718        sendpacket_seterr(sp, "Error getting hardware address: %s", strerror(errno));
719        return NULL;
720    }
721   
722    memcpy(&sp->ether, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
723    close(fd);
724    return(&sp->ether);
725}
726#endif /* HAVE_PF_PACKET */
727
728#if defined HAVE_BPF
729/**
730 * Inner sendpacket_open() method for using BSD's BPF interface
731 */
732static sendpacket_t *
733sendpacket_open_bpf(const char *device, char *errbuf)
734{
735    sendpacket_t *sp;
736    char bpf_dev[10];
737    int dev, mysocket, link_offset, link_type;
738    struct ifreq ifr;
739    struct bpf_version bv;
740    u_int v;
741#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
742    u_int spoof_eth_src = 1;
743#endif
744   
745    assert(device);
746    assert(errbuf);
747    memset(&ifr, '\0', sizeof(struct ifreq));
748   
749    dbg(1, "sendpacket: using BPF");
750    /* open socket */
751    mysocket = -1;
752    for (dev = 0; dev <= 9; dev ++) {
753        memset(bpf_dev, '\0', sizeof(bpf_dev));
754        snprintf(bpf_dev, sizeof(bpf_dev), "/dev/bpf%d", dev);
755        if ((mysocket = open(bpf_dev, O_RDWR, 0)) > 0) {
756            break;
757        }
758    }
759   
760    /* error?? */
761    if (mysocket < 0) {
762        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, 
763            "Unable to open /dev/bpfX: %s", strerror(errno));
764        errbuf[SENDPACKET_ERRBUF_SIZE -1] = '\0';
765        return NULL;
766    }
767   
768    /* get BPF version */
769    if (ioctl(mysocket, BIOCVERSION, (caddr_t)&bv) < 0) {
770        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to get bpf version: %s", strerror(errno));
771        return NULL;
772    }
773
774    if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor != BPF_MINOR_VERSION) {
775        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Kernel's bpf version is out of date.");
776        return NULL;
777    }
778
779    /* attach to device */
780    strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
781    if (ioctl(mysocket, BIOCSETIF, (caddr_t)&ifr) < 0) {
782       snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to bind %s to %s: %s", 
783           bpf_dev, device, strerror(errno));
784       return NULL;
785    }
786   
787    /* get datalink type */
788    if (ioctl(mysocket, BIOCGDLT, (caddr_t)&v) < 0) {
789        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to get datalink type: %s",
790            strerror(errno));
791        return NULL;
792    }
793   
794    /*
795     *  NetBSD and FreeBSD BPF have an ioctl for enabling/disabling
796     *  automatic filling of the link level source address.
797     */
798#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
799    if (ioctl(mysocket, BIOCSHDRCMPLT, &spoof_eth_src) == -1) {
800        snprintf(errbuf, SENDP