Question on SOCK_RAW, implement a bpf->other host tee
Don Bowman
don at sandvine.com
Sat Jul 17 11:51:24 PDT 2004
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);
}
More information about the freebsd-net
mailing list