Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 17 Jul 2004 14:51:21 -0400
From:      Don Bowman <don@sandvine.com>
To:        "'net@freebsd.org'" <net@freebsd.org>
Subject:   Question on SOCK_RAW, implement a bpf->other host tee
Message-ID:  <FE045D4D9F7AED4CBFF1B3B813C85337051D9364@mail.sandvine.com>

next in thread | raw e-mail | index | archive | help

I'm trying to implement a 'tee' which reads
from bpf, and sends matching packets to
another layer-2 adjacent host.

I'm doing this with SOCK_RAW to try and write
the packet back out. The 'sendto' passes,
but i don't see a packet anywhere.

Am i correct that i can hand an arbitrarily
crafted IP packet into sendto, and the stack
will write the ethernet header on, pick an
interface, etc, based on the address in
the sendto?

I have swapped the ip_len, ip_off fields.

The program I have is below. This is on 4.7.
The handler gets called, the packet there looks 
correct, no error on any system call, yet no
output :(

Suggestions?

/*
 * Copyright 2004 Sandvine Incorporated. All rights reserved
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <pcap.h>

void
usage(const char *name)
{
    fprintf(stderr, "Usage: %s [-I input_interface] [-O output_interface]
[-i output_ip(arp for mac)] [-v]\n", name);
    exit(1);
}

typedef struct
{
    int s;
    struct in_addr output_ip;
}
context;

static int verbose;

static void 
handler(unsigned char *ct,
        const struct pcap_pkthdr *hdr,
	const unsigned char *pkt)
{
    struct ip *ip = (struct ip *)(pkt + 14);
    context *ctxt = (context *)ct;
    struct sockaddr_in to;
    memset(&to,0,sizeof(to));
    to.sin_family = AF_INET;
    to.sin_addr = ctxt->output_ip;
    if (verbose)
    {
	fprintf(stderr, "Send %d byte packet\n", hdr->len);
    }
    ip->ip_len = htons(ip->ip_len);
    ip->ip_off = htons(ip->ip_off);
    if (sendto(ctxt->s,
	       ip,
	       hdr->len-14,
	       0,
	       (struct sockaddr *)&to,
	       sizeof(to)) != (hdr->len-14) )
    {
	err(1, "sendto");
    }
}

static int
doit(const char *input_interface,
     const char *output_interface,
     struct in_addr output_ip)
{
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t *in_d, *out_d;
    context ctxt;
    int on = 1;
    struct bpf_program fp;

    in_d = pcap_open_live((char *)input_interface, 1600, 1, 20, errbuf);
    if (in_d == 0)
    {
	errx(1, "open of %s failed: %s", input_interface, errbuf);
    }

    ctxt.output_ip.s_addr = htonl(output_ip.s_addr);
    ctxt.s = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
    if (ctxt.s < 0)
	errx(1, "can't open raw socket");
    if (setsockopt(ctxt.s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on))
< 0)
    {
	err(1,"setsockopt");
    }

    memset(&fp,0,sizeof(fp));
    if (pcap_compile(in_d, &fp, "ip", 0, 0xfffffff0) < 0)
    {
	errx(1, "failed to compile: %s",pcap_geterr(in_d));
    }
    if (pcap_setfilter(in_d, &fp) < 0)
    {
	errx(1, "failed to set filter");
    }

    pcap_loop(in_d, -1, handler, (unsigned char *)&ctxt);
}

int
main(int argc, char *argv[])
{
    int ch;
    char *input_interface = "ipfw0";
    char *output_interface = "em2";
    struct in_addr output_ip;
    output_ip.s_addr = 0;

    while ((ch = getopt(argc, argv, "I:O:i:vh?")) != -1)
    {
	switch (ch) 
	{
	    case 'I':
		input_interface = optarg;
		break;
	    case 'O':
		output_interface = optarg;
		break;
	    case 'i':
		if (inet_aton(optarg,&output_ip) < 0)
		{
		    errx(1, "unknown ip %s", optarg);
		}
		break;
	    case 'v':
		verbose = 1;
		break;
	    case 'h':
	    case '?':
	    default:
		usage(argv[0]);
	}
    }
    if (verbose)
	fprintf(stderr, "%s->%s(%s)\n",
input_interface,output_interface,inet_ntoa(output_ip));
    return doit(input_interface,output_interface,output_ip);
}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?FE045D4D9F7AED4CBFF1B3B813C85337051D9364>