Annotation of nono/host/netdriver_bpf.cpp, revision 1.1.1.6

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.