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