diff options
Diffstat (limited to 'fw/test/rawether.c')
| -rw-r--r-- | fw/test/rawether.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/fw/test/rawether.c b/fw/test/rawether.c new file mode 100644 index 0000000..540d0b6 --- /dev/null +++ b/fw/test/rawether.c @@ -0,0 +1,97 @@ +/* + * rawether - put one ethernet frame on the wire, addressed as told. + * + * A stack will only ever address a frame to the mac it resolved, so a + * frame addressed to somebody else has to be forged. That is the only + * way to ask a firewall on a card whether it is looking at frames that + * are not for it. + * + * rawether /net/ether1 <dstmac> <srcip> <dstip> + * + * The payload is an icmp echo request, which is enough to be counted. + */ +#include <u.h> +#include <libc.h> +#include <ip.h> + +enum { Ehdrlen = 14, Eminlen = 60, Etip4 = 0x0800 }; + +static ushort +csum(uchar *p, int n) +{ + ulong s; + int i; + + s = 0; + for(i = 0; i+1 < n; i += 2) + s += (p[i]<<8) | p[i+1]; + if(i < n) + s += p[i]<<8; + while(s >> 16) + s = (s & 0xFFFF) + (s >> 16); + return ~s; +} + +void +main(int argc, char **argv) +{ + uchar f[Eminlen], dst[6], src[6], sip[IPaddrlen], dip[IPaddrlen]; + char path[128], buf[64]; + int cfd, dfd, n, conn; + + if(argc != 5){ + fprint(2, "usage: rawether /net/etherN dstmac srcip dstip\n"); + exits("usage"); + } + if(parseether(dst, argv[2]) < 0) + sysfatal("%s: bad ethernet address", argv[2]); + if(parseip(sip, argv[3]) == -1 || parseip(dip, argv[4]) == -1) + sysfatal("bad ip address"); + + snprint(path, sizeof path, "%s/clone", argv[1]); + if((cfd = open(path, ORDWR)) < 0) + sysfatal("open %s: %r", path); + if((n = read(cfd, buf, sizeof buf - 1)) <= 0) + sysfatal("read %s: %r", path); + buf[n] = '\0'; + conn = atoi(buf); + if(fprint(cfd, "connect -1") < 0) + sysfatal("connect -1: %r"); + snprint(path, sizeof path, "%s/%d/data", argv[1], conn); + if((dfd = open(path, ORDWR)) < 0) + sysfatal("open %s: %r", path); + snprint(path, sizeof path, "%s/addr", argv[1]); + if((n = open(path, OREAD)) < 0) + sysfatal("open addr: %r"); + if(read(n, buf, 12) != 12) + sysfatal("read addr: %r"); + close(n); + buf[12] = '\0'; + if(parseether(src, buf) < 0) + sysfatal("unparseable card address %s", buf); + + memset(f, 0, sizeof f); + memmove(f, dst, 6); + memmove(f+6, src, 6); + f[12] = Etip4 >> 8; + f[13] = Etip4; + + f[14] = 0x45; /* v4, 20 byte header */ + hnputs(f+16, 28); /* total length */ + f[22] = 64; /* ttl */ + f[23] = 1; /* icmp */ + memmove(f+26, sip+IPv4off, 4); + memmove(f+30, dip+IPv4off, 4); + hnputs(f+24, csum(f+14, 20)); + + f[34] = 8; /* echo request */ + hnputs(f+38, 0x1234); /* id */ + hnputs(f+40, 1); /* seq */ + hnputs(f+36, csum(f+34, 8)); + + if(write(dfd, f, sizeof f) != sizeof f) + sysfatal("write: %r"); + fmtinstall('E', eipfmt); + print("sent %d bytes to %E\n", (int)sizeof f, dst); + exits(nil); +} |
