|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2019 [email protected]
4: //
5:
6: #include "header.h"
7: #include "netdriver_bpf.h"
8: #include "cvprompt.h"
9: #include "mystring.h"
10: #include <fcntl.h>
11: #include <ifaddrs.h>
12: #include <sys/ioctl.h>
13: #include <sys/socket.h>
14: #if defined(HAVE_SYS_EVENT_H)
15: #include <sys/event.h>
16: #endif
17: #if defined(HAVE_KQUEUE_SYS_EVENT_H)
18: #include <kqueue/sys/event.h>
19: #endif
20: #include <net/bpf.h>
21: #include <net/if.h>
22: #include <net/if_dl.h>
23: #include <net/if_types.h>
24:
25: // コンストラクタ
26: NetDriverBPF::NetDriverBPF(EthernetDevice *p,
27: std::mutex *m, std::condition_variable *c)
28: : inherited("BPF", p, m, c)
29: {
30: fd = -1;
31: }
32:
33: // デストラクタ
34: NetDriverBPF::~NetDriverBPF()
35: {
36: Close();
37: }
38:
39: // 初期化 & オープン
40: bool
41: NetDriverBPF::Init()
42: {
43: struct ifreq ifr;
44: struct bpf_program prog;
45: u_int val;
46: struct bpf_insn insn[] = {
47: // すべてのパケットを全長受信
48: BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
49: };
50:
51: // XXX tap はデバイスを開くとインタフェースが出来る、という方向だが、
52: // bpf はインタフェースを指定してデバイスを開く、という方向で、逆…。
53:
54: if (ifname.empty()) {
55: // インタフェース指定がなければそれっぽいのを探すか
56: ifname = FindInterface();
57: if (ifname.empty()) {
58: warn("NetDriverBPF: no interface specified");
59: return false;
60: }
61: }
62:
63: // 最大値は適当
64: fd = -1;
65: for (int i = -1; i < 10; i++) {
66: // i == -1 なら /dev/bpf、0..10 は /dev/bpfN。
67: // まず /dev/bpf を cloning デバイスだと思って開いてみる。
68: // そうでなければ従来どおり 0 から順番に試してみる。
69: if (i == -1) {
70: devpath = "/dev/bpf";
71: } else {
72: devpath = string_format("/dev/bpf%d", i);
73: }
74:
75: fd = open(devpath.c_str(), O_RDWR);
76: if (fd == -1) {
77: warn("NetDriverBPF.Open: skip %s", devpath.c_str());
78: continue;
79: }
80: break;
81: }
82: if (fd == -1) {
83: warnx("NetDriverBPF.Open: no bpf device available");
84: return false;
85: }
86:
87: // インタフェースにバインド
88: memset(&ifr, 0, sizeof(ifr));
89: strlcpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
90: if (ioctl(fd, BIOCSETIF, &ifr) == -1) {
91: warn("NetDriverBPF.Open: %s(%s) BIOCSETIF failed",
92: devpath.c_str(), ifname.c_str());
93: goto abort;
94: }
95: // バインドまで出来たところでログを出しておきたい
96: // XXX 本当は warn じゃないよね
97: warnx("NetDriverBPF.Open: %s opened for %s",
98: devpath.c_str(), ifname.c_str());
99:
100: if (ioctl(fd, BIOCPROMISC, (void *)0) == -1) {
101: warn("NetDriverBPF.Open: %s(%s): BIOCPROMISC failed",
102: devpath.c_str(), ifname.c_str());
103: goto abort;
104: }
105:
106: val = 1;
107: if (ioctl(fd, BIOCIMMEDIATE, &val) == -1) {
108: warn("NetDriverBPF.Open: %s(%s): BIOCIMMEDIATE failed",
109: devpath.c_str(), ifname.c_str());
110: goto abort;
111: }
112:
113: if (ioctl(fd, BIOCSHDRCMPLT, &val) == -1) {
114: warn("NetDriverBPF.Open: %s(%s): BIOCSHDRCMPLT failed",
115: devpath.c_str(), ifname.c_str());
116: goto abort;
117: }
118:
119: // XXX BIOCFEEDBACK...
120: warn("NetDriverBPF.Open: %s(%s): ローカルホストとのみ通信はできません",
121: devpath.c_str(), ifname.c_str());
122:
123: // フィルタをセット
124: prog.bf_len = countof(insn);
125: prog.bf_insns = insn;
126: if (ioctl(fd, BIOCSETF, &prog) == -1) {
127: warn("NetDriverBPF.Open: %s(%s): BIOCSETF failed",
128: devpath.c_str(), ifname.c_str());
129: goto abort;
130: }
131:
132: // バッファサイズを取得
133: if (ioctl(fd, BIOCGBLEN, &bpfbuflen) == -1) {
134: warn("NetDriverBPF.Open: %s(%s): BIOCGBLEN failed",
135: devpath.c_str(), ifname.c_str());
136: goto abort;
137: }
138:
139: // 受信用バッファを確保
140: try {
1.1.1.2 ! root 141: bpfbuf.reset(new char [bpfbuflen]);
1.1 root 142: } catch (...) {
143: warnx("NetDriverBPF.Open: %s(%s): memory allocation failed",
144: devpath.c_str(), ifname.c_str());
145: goto abort;
146: }
147:
148: // オープンできたので受信スレッド起動。
149: if (InitRecvThread() == false) {
150: goto abort;
151: }
152:
153: // bpf では ifup スクリプトは実行しない
154:
155: return true;
156:
157: abort:
158: close(fd);
159: fd = -1;
160: return false;
161: }
162:
163: // クローズ
164: // (private)
165: void
166: NetDriverBPF::Close()
167: {
168: if (IsOpen()) {
169: close(fd);
170: fd = -1;
171: }
172: }
173:
174: // パケットを送信する
175: bool
176: NetDriverBPF::SendPacket(const std::vector<uint8>& data)
177: {
178: int n;
179:
180: assert(IsOpen());
181:
182: putlog(2, "SendPacket %zu bytes", data.size());
183: tx_pkts++;
184: tx_bytes += data.size();
185:
186: n = write(fd, data.data(), data.size());
187: if (n == -1) {
188: warn("NetDriverBPF.SendPacket: write failed: fd=%d datalen=%zu",
189: fd, data.size());
190: return false;
191: }
192:
193: if (n < (int)data.size()) {
194: return false;
195: }
196: return true;
197: }
198:
199: // 最初に見付かった使えそうなインタフェース名を返す。
200: // 物理インタフェースが明らかに1つしかないところで、
201: // インタフェース名の指定を省略できるようにするため。
202: std::string
203: NetDriverBPF::FindInterface()
204: {
205: char name[IFNAMSIZ];
206: struct ifaddrs *ifa_list, *ifa;
207: struct sockaddr_dl *dl;
208:
209: if (getifaddrs(&ifa_list) == -1) {
210: return "";
211: }
212:
213: name[0] = '\0';
214: for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
215: dl = (struct sockaddr_dl *)ifa->ifa_addr;
216: if ((ifa->ifa_flags & IFF_UP) != 0 && dl->sdl_type == IFT_ETHER) {
217: strlcpy(name, ifa->ifa_name, sizeof(name));
218: break;
219: }
220: }
221: freeifaddrs(ifa_list);
222:
223: return std::string(name);
224: }
225:
226: // 受信スレッド
227: void
228: NetDriverBPF::ThreadRun()
229: {
230: struct kevent kev;
231: int kq;
232: int r;
233:
234: kq = kqueue();
235: if (kq == -1) {
236: warn("kqueue failed");
237: return;
238: }
239:
240: EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, (kevent_udata_t)0);
241: r = kevent_set(kq, &kev, 1);
242: if (r == -1) {
243: warn("kevent_set(fd=%d) failed", fd);
244: close(kq);
245: return;
246: }
247:
248: for (;;) {
249: int n;
250: char *bpfptr;
251: int bpfcaplen;
252:
253: // 何か起きるまで待つ
254: r = kevent_poll(kq, &kev, 1, NULL);
255: if (r == -1) {
256: if (errno == EINTR) {
257: continue;
258: }
259: // XXX ?
260: warn("NetDriverBPF.ThreadRun: kevent_poll failed");
261: break;
262: }
263:
264: // 自動的にデバイスに着信があったことになるはず
265: assert(r > 0);
266:
1.1.1.2 ! root 267: n = read(fd, bpfbuf.get(), bpfbuflen);
1.1 root 268: if (n == -1) {
269: if (errno == EINTR) {
270: continue;
271: }
272: warn("NetDriverBPF.ThreadRun: read(fd=%d) failed", fd);
273: break;
274: }
275: if (n == 0) { // EOF
276: return;
277: }
1.1.1.2 ! root 278: bpfptr = bpfbuf.get();
1.1 root 279: bpfcaplen = n;
280:
1.1.1.2 ! root 281: while (bpfptr < bpfbuf.get() + bpfcaplen) {
1.1 root 282: uint8 buf[1600];
283:
284: // BPF ヘッダを除いた部分
285: struct bpf_hdr *bh = (struct bpf_hdr *)bpfptr;
286: n = bh->bh_caplen;
287: memcpy(buf, bpfptr + bh->bh_hdrlen, n);
288:
289: // 次のフレームの先頭を指す
290: int framelen = BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
291: bpfptr += framelen;
292:
293: // 60バイトパディングされないまま読み出せたらここでパディングする。
294: if (n < 60) {
295: memset(buf + n, 0, 60 - n);
296: n = 60;
297: }
298:
299: // CRC XXX 計算すること
300: memset(buf + n, 0, 4);
301: n += 4;
302:
303: // 受信処理に引き渡す
304: // ただしデバッガプロンプトで停止してる状態なら VM に干渉しない。
305: if (parent->RecvEnabled && gCVPrompt->IsPrompt() == false) {
306: putlog(2, "RecvPacket %d bytes", n);
307: rx_pkts++;
308: rx_bytes += n;
309:
310: qvector<uint8> recvbuf(buf, buf + n);
311: parent->RecvPacket(recvbuf);
312: }
313: }
314: }
315: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.