1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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);
}
|