Hi Folks,
Attached is an updated br_input.c which is based on
* $Id: br_input.c,v 1.9.2.1 2001/12/24 04:50:05 davem Exp $
(included in the 2.4.20 kernel). This patch looks at each packet passing
through the bridge, and finds ICMP packets with payloads that have a block
of zeros in them. If it finds space, the current host's MAC address is
written into the payload.
I have been using this to debug a wireless network that runs the bridge
code.. Normally, 'ping' formulates ICMP echo request/replies with payloads
having increasing sequences (0,1,2,etc.). However, some versions of ping let
you specify a pattern in the payload. If the pattern sent out in the ICMP
echo request doesn't match the reply, ping complains and prints out the diff.
l2trace parses this and prints out the sequence. The 'ping' I'm using is from
OpenBSD 3.2, but I think linux ping behaves exactly the same way.
Thus..normally, the bridge doesn't do anything to packets that pass through.
However, when it sees ICMP packets with zeros in their payload, it writes the
MAC in there.
% l2trace 192.168.10.44
0 4 e2 63 65 6f
0 4 e2 63 65 5e
0 4 e2 63 65 5e
0 4 e2 63 65 6f
%
Hopefully this little patch will be useful to somebody else too! =)
Jack
/*
* Handle incoming frames
* Linux ethernet bridge
*
* Authors:
* Lennert Buytenhek <[EMAIL PROTECTED]>
*
* $Id: br_input.c,v 1.9.2.1 2001/12/24 04:50:05 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
#include <linux/netfilter_bridge.h>
#include "br_private.h"
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/in.h>
#include <net/checksum.h>
unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
static int br_pass_frame_up_finish(struct sk_buff *skb)
{
netif_rx(skb);
return 0;
}
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
struct net_device *indev;
br->statistics.rx_packets++;
br->statistics.rx_bytes += skb->len;
indev = skb->dev;
skb->dev = &br->dev;
skb->pkt_type = PACKET_HOST;
skb_push(skb, ETH_HLEN);
skb->protocol = eth_type_trans(skb, &br->dev);
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
br_pass_frame_up_finish);
}
static int br_handle_frame_finish(struct sk_buff *skb)
{
struct net_bridge *br;
unsigned char *dest;
struct net_bridge_fdb_entry *dst;
struct net_bridge_port *p;
int passedup;
dest = skb->mac.ethernet->h_dest;
p = skb->dev->br_port;
if (p == NULL)
goto err_nolock;
br = p->br;
read_lock(&br->lock);
if (skb->dev->br_port == NULL)
goto err;
passedup = 0;
if (br->dev.flags & IFF_PROMISC) {
struct sk_buff *skb2;
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2 != NULL) {
passedup = 1;
br_pass_frame_up(br, skb2);
}
}
if (dest[0] & 1) {
br_flood_forward(br, skb, !passedup);
if (!passedup)
br_pass_frame_up(br, skb);
goto out;
}
dst = br_fdb_get(br, dest);
if (dst != NULL && dst->is_local) {
if (!passedup)
br_pass_frame_up(br, skb);
else
kfree_skb(skb);
br_fdb_put(dst);
goto out;
}
if (dst != NULL) {
br_forward(dst->dst, skb);
br_fdb_put(dst);
goto out;
}
br_flood_forward(br, skb, 0);
out:
read_unlock(&br->lock);
return 0;
err:
read_unlock(&br->lock);
err_nolock:
kfree_skb(skb);
return 0;
}
void br_handle_frame(struct sk_buff *skb)
{
struct net_bridge *br;
unsigned char *dest;
struct net_bridge_port *p;
// jack vars
int i,run,slot;
unsigned char c1,c2;
unsigned int checksum;
// jack code
// skb->nh.iph->protocol -- 1 = ICMP, 6 = TCP
// skb->h.icmph->type -- 0 = echo reply, 8 = echo request
if (skb->mac.ethernet->h_proto == 0x0008) {
// printk("ip %d %.4x\n",skb->len,skb->mac.ethernet->h_proto);
// printk("ip %d: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x ->
%.2x:%.2x:%.2x:%.2x:%.2x:%.2x \n",
// skb->len,
// skb->mac.ethernet->h_source[0],
// skb->mac.ethernet->h_source[1],
// skb->mac.ethernet->h_source[2],
// skb->mac.ethernet->h_source[3],
// skb->mac.ethernet->h_source[4],
// skb->mac.ethernet->h_source[5],
// skb->mac.ethernet->h_dest[0],
// skb->mac.ethernet->h_dest[1],
// skb->mac.ethernet->h_dest[2],
// skb->mac.ethernet->h_dest[3],
// skb->mac.ethernet->h_dest[4],
// skb->mac.ethernet->h_dest[5]);
// printk(">>");
// for (i = 0 ; i < skb->len ; i++) printk(" %.2x",skb->mac.raw[i]);
// printk("\n");
// printk(">>");
// for (i = 45 ; i < skb->len && i < 55 ; i++) printk(" %.2x
(%d)",skb->mac.raw[i],i);
// printk("\n");
// printk("ip proto %d len %d\n", skb->nh.iph->protocol,
skb->nh.iph->ihl);
// printk("ip src %.2x.%.2x.%.2x.%.2x dest %.2x.%.2x.%.2x.%.2x\n",
// ((unsigned char *)(&skb->nh.iph->saddr))[0],
// ((unsigned char *)(&skb->nh.iph->saddr))[1],
// ((unsigned char *)(&skb->nh.iph->saddr))[2],
// ((unsigned char *)(&skb->nh.iph->saddr))[3],
// ((unsigned char *)(&skb->nh.iph->daddr))[0],
// ((unsigned char *)(&skb->nh.iph->daddr))[1],
// ((unsigned char *)(&skb->nh.iph->daddr))[2],
// ((unsigned char *)(&skb->nh.iph->daddr))[3]);
if (skb->nh.iph->protocol == IPPROTO_ICMP) {
// icmp message
c1 = skb->mac.raw[36];
c2 = skb->mac.raw[37];
// printk("icmp type %.2x, code %.2x, chk %.2x %.2x\n",
// skb->mac.raw[34],skb->mac.raw[35], c1, c2);
// find the first spot in the payload that's 6 bytes of zeros
for (i = 50, run = 0 ; i < skb->len ; i++) {
if (skb->mac.raw[i] == 0) run++;
else run = 0;
if (run == skb->dev->addr_len) break;
}
if (run == skb->dev->addr_len) {
slot = i - skb->dev->addr_len + 1;
// printk("slot starts at %d\n",slot);
// copy in this station's address
for ( i = 0; i < skb->dev->addr_len ; i++)
skb->mac.raw[slot+i] = skb->dev->dev_addr[i];
// recompute the ip checksum
// skb->nh.iph->check = 0;
// skb->nh.iph->check = ip_fast_csum((unsigned char
*)skb->nh.iph, skb->nh.iph->ihl);
// recompute the icmp checksum
skb->mac.raw[36] = 0;
skb->mac.raw[37] = 0;
checksum = csum_partial(&skb->mac.raw[34],skb->len -
34,0);
// printk("new ck = %.4x", checksum);
checksum = csum_fold(checksum);
// printk(" new folded = %.4x", checksum);
// put the old checksum back into the packet
// skb->mac.raw[36] = c1;
// skb->mac.raw[37] = c2;
// insert the new checksum into the packet
c1 = ((unsigned char *)&checksum)[0];
c2 = ((unsigned char *)&checksum)[1];
// printk(" c1 = %.2x, c2 = %.2x\n", c1, c2);
skb->mac.raw[36] = c1;
skb->mac.raw[37] = c2;
} else {
// printk("no slot found!\n");
}
}
// printk("(%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) [%d]\n",
// skb->dev->dev_addr[0],
// skb->dev->dev_addr[1],
// skb->dev->dev_addr[2],
// skb->dev->dev_addr[3],
// skb->dev->dev_addr[4],
// skb->dev->dev_addr[5],
// skb->dev->addr_len);
}
// if (skb->mac.ethernet->h_proto == 0x0608) {
// printk("arp %d %.4x\n",skb->len,skb->mac.ethernet->h_proto);
// }
// skb->mac.ethernet->h_dest -- 6 bytes
// skb->mac.ethernet->h_source -- 6 bytes
// skb->mac.ethernet->h_proto -- 2 bytes "0800" for IP
// orig code
dest = skb->mac.ethernet->h_dest;
p = skb->dev->br_port;
if (p == NULL)
goto err_nolock;
br = p->br;
read_lock(&br->lock);
if (skb->dev->br_port == NULL)
goto err;
if (!(br->dev.flags & IFF_UP) ||
p->state == BR_STATE_DISABLED)
goto err;
if (skb->mac.ethernet->h_source[0] & 1)
goto err;
if (p->state == BR_STATE_LEARNING ||
p->state == BR_STATE_FORWARDING)
br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
if (br->stp_enabled &&
!memcmp(dest, bridge_ula, 5) &&
!(dest[5] & 0xF0))
goto handle_special_frame;
if (p->state == BR_STATE_FORWARDING) {
NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish);
read_unlock(&br->lock);
return;
}
err:
read_unlock(&br->lock);
err_nolock:
kfree_skb(skb);
return;
handle_special_frame:
if (!dest[5]) {
br_stp_handle_bpdu(skb);
read_unlock(&br->lock);
return;
}
read_unlock(&br->lock);
kfree_skb(skb);
}
#!/usr/bin/perl
my $ip;
my $ping = "/sbin/ping";
my %ip2desc;
$ip2desc{'52'} = "garage";
$ip2desc{'51'} = "doniach front";
$ip2desc{'39'} = "biz window";
$ip2desc{'48'} = "doniach upstairs";
$ip2desc{'49'} = "college & amherst";
$ip2desc{'36'} = "jack window";
my %mac2ip;
$mac2ip{'0 4 e2 63 65 6f'} = 36;
$mac2ip{'0 4 e2 63 65 62'} = 52;
$mac2ip{'0 4 e2 63 65 5e'} = 39;
$mac2ip{'0 4 e2 63 65 5b'} = 49;
$mac2ip{'0 4 e2 63 65 5c'} = 51;
$mac2ip{'0 4 e2 63 65 6e'} = 48;
while (@ARGV) {
my $arg = shift(@ARGV);
if ($arg eq "-v") {
$verbose = 1;
} else {
if ($ip eq "") {
$ip = $arg;
} else {
&usage;
}
}
}
if ($ip eq "") { &usage; }
my $t = `$ping -s 256 -c 1 -p 00 $ip`;
my $i = 1;
#print("===>\n");
#print($t);
#print("===>\n");
my @lines = split(/\n/,$t);
# dump the first four lines
shift(@lines);
shift(@lines);
shift(@lines);
shift(@lines);
# dump the last three lines
pop(@lines);
pop(@lines);
pop(@lines);
#print("yo");
#foreach $f (@lines) { print("$f\n"); }
#print("yo");
# recombine
$t = shift(@lines);
foreach $f (@lines) { $t = $t . "\n" . $f; }
my @s = split(/\s+/,$t);
# dump the first 8
for(my $j = 0 ; $j <= 8 ; $j++) { shift(@s); }
$t = "";
foreach $f (@s) {
if ($t ne "") { $t = $t . " $f"; }
else { $t = $f; }
if ($i % 6 == 0) {
if ($t ne "0 0 0 0 0 0") {
my $ip = $mac2ip{$t};
my $desc = $ip2desc{$ip};
print("$t $desc\n");
}
$t = "";
}
$i++;
}
sub usage { die("usage: $0 <ip>\n"); }
_______________________________________________
Bridge mailing list
[EMAIL PROTECTED]
http://www.math.leidenuniv.nl/mailman/listinfo/bridge