|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "netdriver_bpf.h"
1.1.1.4 root 8: #include "autofd.h"
1.1 root 9: #include <fcntl.h>
10: #include <ifaddrs.h>
11: #include <sys/ioctl.h>
12: #include <sys/socket.h>
13: #include <net/bpf.h>
14: #include <net/if.h>
15: #include <net/if_dl.h>
16: #include <net/if_types.h>
17:
18: // コンストラクタ
1.1.1.5 ! root 19: NetDriverBPF::NetDriverBPF(EthernetDevice *parent_, int loglevel_,
! 20: const std::string& ifname_)
! 21: : inherited("BPF", parent_, loglevel_)
1.1 root 22: {
1.1.1.5 ! root 23: ifname = ifname_;
! 24: if (ifname.empty()) {
! 25: ifname = "auto";
! 26: }
1.1 root 27: }
28:
29: // デストラクタ
30: NetDriverBPF::~NetDriverBPF()
31: {
32: Close();
33: }
34:
1.1.1.5 ! root 35: // ドライバ初期化 & オープン
1.1 root 36: bool
1.1.1.5 ! root 37: NetDriverBPF::InitDriver()
1.1 root 38: {
39: struct ifreq ifr;
40: struct bpf_program prog;
41: u_int val;
42: struct bpf_insn insn[] = {
43: // すべてのパケットを全長受信
44: BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
45: };
46:
1.1.1.5 ! root 47: putmsg(1, "trying bpf...");
! 48: putmsg(1, "argument: ifname=\"%s\"", ifname.c_str());
1.1 root 49:
1.1.1.5 ! root 50: if (ifname == "auto") {
1.1 root 51: // インタフェース指定がなければそれっぽいのを探すか
52: ifname = FindInterface();
53: if (ifname.empty()) {
1.1.1.5 ! root 54: errmsg = "auto could not find a suitable interface";
! 55: goto abort;
1.1 root 56: }
1.1.1.5 ! root 57: putmsg(1, "auto-selected ifname: \"%s\"", ifname.c_str());
1.1 root 58: }
59:
60: // 最大値は適当
61: fd = -1;
62: for (int i = -1; i < 10; i++) {
63: // i == -1 なら /dev/bpf、0..10 は /dev/bpfN。
64: // まず /dev/bpf を cloning デバイスだと思って開いてみる。
65: // そうでなければ従来どおり 0 から順番に試してみる。
66: if (i == -1) {
67: devpath = "/dev/bpf";
68: } else {
69: devpath = string_format("/dev/bpf%d", i);
70: }
71:
72: fd = open(devpath.c_str(), O_RDWR);
1.1.1.4 root 73: if (fd < 0) {
74: // ファイルがないのを表示したら結構うるさいので除く
75: if (errno != ENOENT) {
1.1.1.5 ! root 76: putmsg(1, "open %s: %s", devpath.c_str(), strerror(errno));
1.1.1.4 root 77: }
1.1 root 78: continue;
79: }
1.1.1.5 ! root 80: // 成功したら抜ける
1.1 root 81: break;
82: }
1.1.1.4 root 83: if (fd < 0) {
1.1.1.5 ! root 84: errmsg = "no bpf devices available";
! 85: goto abort;
1.1 root 86: }
87:
88: // インタフェースにバインド
89: memset(&ifr, 0, sizeof(ifr));
90: strlcpy(ifr.ifr_name, ifname.c_str(), sizeof(ifr.ifr_name));
91: if (ioctl(fd, BIOCSETIF, &ifr) == -1) {
1.1.1.5 ! root 92: errmsg = string_format("%s(%s): BIOCSETIF: %s",
! 93: devpath.c_str(), ifname.c_str(), strerror(errno));
1.1 root 94: goto abort;
95: }
96:
97: if (ioctl(fd, BIOCPROMISC, (void *)0) == -1) {
1.1.1.5 ! root 98: errmsg = string_format("%s(%s): %s: %s",
! 99: devpath.c_str(), ifname.c_str(), "BIOCPROMISC", strerror(errno));
1.1 root 100: goto abort;
101: }
102:
103: val = 1;
104: if (ioctl(fd, BIOCIMMEDIATE, &val) == -1) {
1.1.1.5 ! root 105: errmsg = string_format("%s(%s): %s: %s",
! 106: devpath.c_str(), ifname.c_str(), "BIOCIMMEDIATE", strerror(errno));
1.1 root 107: goto abort;
108: }
109:
110: if (ioctl(fd, BIOCSHDRCMPLT, &val) == -1) {
1.1.1.5 ! root 111: errmsg = string_format("%s(%s): %s: %s",
! 112: devpath.c_str(), ifname.c_str(), "BIOCSHDRCMPLT", strerror(errno));
1.1 root 113: goto abort;
114: }
115:
116: // フィルタをセット
117: prog.bf_len = countof(insn);
118: prog.bf_insns = insn;
119: if (ioctl(fd, BIOCSETF, &prog) == -1) {
1.1.1.5 ! root 120: errmsg = string_format("%s(%s): %s: %s",
! 121: devpath.c_str(), ifname.c_str(), "BIOCSETF", strerror(errno));
1.1 root 122: goto abort;
123: }
124:
125: // バッファサイズを取得
126: if (ioctl(fd, BIOCGBLEN, &bpfbuflen) == -1) {
1.1.1.5 ! root 127: errmsg = string_format("%s(%s): %s: %s",
! 128: devpath.c_str(), ifname.c_str(), "BIOCGBLEN", strerror(errno));
1.1 root 129: goto abort;
130: }
131:
132: // 受信用バッファを確保
133: try {
1.1.1.5 ! root 134: bpfbuf.reset(new uint8 [bpfbuflen]);
1.1 root 135: } catch (...) {
1.1.1.5 ! root 136: errmsg = "memory allocation failed";
1.1 root 137: goto abort;
138: }
139:
1.1.1.5 ! root 140: putmsg(1, "opened %s for %s", devpath.c_str(), ifname.c_str());
! 141: putmsg(1, "warning: communicating with the localhost is not possible");
1.1 root 142:
143: // bpf では ifup スクリプトは実行しない
144:
145: return true;
146:
147: abort:
1.1.1.5 ! root 148: putmsg(1, "%s", errmsg.c_str());
! 149: Close();
1.1 root 150: return false;
151: }
152:
153: // クローズ
154: // (private)
155: void
156: NetDriverBPF::Close()
157: {
158: if (IsOpen()) {
159: close(fd);
160: fd = -1;
161: }
162: }
163:
1.1.1.5 ! root 164: // モニタ (ドライバ依存情報のみ)
! 165: void
! 166: NetDriverBPF::MonitorUpdateMD(TextScreen& screen)
! 167: {
! 168: screen.Print(0, 1, "Device : %s", devpath.c_str());
! 169: screen.Print(0, 2, "Interface: %s", ifname.c_str());
! 170: }
! 171:
1.1 root 172: // パケットを送信する
173: bool
174: NetDriverBPF::SendPacket(const std::vector<uint8>& data)
175: {
176: int n;
177:
178: assert(IsOpen());
179:
180: putlog(2, "SendPacket %zu bytes", data.size());
181: tx_pkts++;
182: tx_bytes += data.size();
183:
184: n = write(fd, data.data(), data.size());
185: if (n == -1) {
1.1.1.5 ! root 186: putmsg(0, "%s: write failed: fd=%d datalen=%zu: %s",
! 187: __func__, fd, data.size(), strerror(errno));
1.1 root 188: return false;
189: }
190:
191: if (n < (int)data.size()) {
192: return false;
193: }
194: return true;
195: }
196:
197: // 最初に見付かった使えそうなインタフェース名を返す。
198: // 物理インタフェースが明らかに1つしかないところで、
199: // インタフェース名の指定を省略できるようにするため。
200: std::string
1.1.1.5 ! root 201: NetDriverBPF::FindInterface() const
1.1 root 202: {
203: char name[IFNAMSIZ];
204: struct ifaddrs *ifa_list, *ifa;
205: struct sockaddr_dl *dl;
206:
207: if (getifaddrs(&ifa_list) == -1) {
208: return "";
209: }
210:
211: name[0] = '\0';
212: for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
213: dl = (struct sockaddr_dl *)ifa->ifa_addr;
214: if ((ifa->ifa_flags & IFF_UP) != 0 && dl->sdl_type == IFT_ETHER) {
215: strlcpy(name, ifa->ifa_name, sizeof(name));
216: break;
217: }
218: }
219: freeifaddrs(ifa_list);
220:
221: return std::string(name);
222: }
223:
1.1.1.5 ! root 224: // パケットを受信する
! 225: ssize_t
! 226: NetDriverBPF::RecvPacket()
1.1 root 227: {
1.1.1.5 ! root 228: uint8 *buf = bpfbuf.get();
! 229: uint8 *bpfptr = buf;
! 230: ssize_t n;
1.1 root 231:
1.1.1.5 ! root 232: n = read(fd, buf, bpfbuflen);
! 233: if (n <= 0) {
! 234: return n;
! 235: }
1.1 root 236:
1.1.1.5 ! root 237: while (bpfptr < buf + n) {
! 238: // BPF ヘッダを除いた部分が 1 パケット
! 239: struct bpf_hdr *bh = (struct bpf_hdr *)bpfptr;
! 240: RecvEnqueue(bpfptr + bh->bh_hdrlen, bh->bh_caplen);
1.1 root 241:
1.1.1.5 ! root 242: // 次のフレームの先頭を指す
! 243: int framelen = BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
! 244: bpfptr += framelen;
1.1 root 245: }
1.1.1.5 ! root 246: return n;
1.1 root 247: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.