Annotation of nono/host/netdriver_afpacket.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2021 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: // AF_PACKET を用いたドライバ
        !             8: // Linux 2.2 以降専用
        !             9: 
        !            10: #include "netdriver_afpacket.h"
        !            11: #include "autofd.h"
        !            12: #include <ifaddrs.h>
        !            13: #include <sys/socket.h>
        !            14: #include <sys/ioctl.h>
        !            15: #include <net/if.h>
        !            16: #include <net/if_arp.h>
        !            17: 
        !            18: // コンストラクタ
        !            19: NetDriverAFPacket::NetDriverAFPacket(EthernetDevice *parent_, int loglevel_,
        !            20:        const std::string& ifname_)
        !            21:        : inherited("AFPacket", parent_, loglevel_)
        !            22: {
        !            23:        ifname = ifname_;
        !            24:        if (ifname.empty()) {
        !            25:                ifname = "auto";
        !            26:        }
        !            27: }
        !            28: 
        !            29: // デストラクタ
        !            30: NetDriverAFPacket::~NetDriverAFPacket()
        !            31: {
        !            32:        Close();
        !            33: }
        !            34: 
        !            35: // ドライバ初期化 & オープン
        !            36: bool
        !            37: NetDriverAFPacket::InitDriver()
        !            38: {
        !            39:        packet_mreq mreq {};
        !            40:        int len;
        !            41:        socklen_t so_len;
        !            42: 
        !            43:        putmsg(1, "trying afpacket...");
        !            44:        putmsg(1, "argument: ifname=\"%s\"", ifname.c_str());
        !            45: 
        !            46:        sll.sll_family = AF_PACKET;
        !            47:        sll.sll_protocol = htons(ETH_P_ALL);
        !            48:        sll.sll_ifindex = SelectInterface();
        !            49:        if (sll.sll_ifindex == 0) {
        !            50:                goto abort;
        !            51:        }
        !            52: 
        !            53:        // bind するまでの期間、このソケットにはシステムのすべての
        !            54:        // インタフェースからのパケットが着信することに注意。
        !            55:        fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        !            56:        if (fd < 0) {
        !            57:                errmsg = string_format("%s: %s", "socket(AF_PACKET)", strerror(errno));
        !            58:                putmsg(1, "%s", errmsg.c_str());
        !            59:                if (errno == EPERM) {
        !            60:                        // Linux では setcap(8) が必要。分かりづらいのでメッセージを出すが
        !            61:                        // その例示より先に errmsg を表示したい。
        !            62:                        warnx("%s", errmsg.c_str());
        !            63:                        errmsg.clear();
        !            64: 
        !            65:                        fprintf(stderr,
        !            66:                                " ** Set CAP_NET_RAW capability to the nono executable file.\n"
        !            67:                                " **  ex) sudo setcap cap_net_raw=ep path/to/%s\n",
        !            68:                                getprogname());
        !            69:                }
        !            70:                return false;
        !            71:        }
        !            72: 
        !            73:        if (bind(fd, (const sockaddr *)&sll, sizeof(sll)) != 0) {
        !            74:                errmsg = string_format("bind(%s): %s", ifname.c_str(), strerror(errno));
        !            75:                goto abort;
        !            76:        }
        !            77: 
        !            78:        // PROMISC セット
        !            79:        mreq.mr_ifindex = sll.sll_ifindex;
        !            80:        mreq.mr_type = PACKET_MR_PROMISC;
        !            81:        if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
        !            82:                &mreq, sizeof(mreq)) != 0) {
        !            83:                errmsg = string_format("%s: %s", "set PROMISC", strerror(errno));
        !            84:                goto abort;
        !            85:        }
        !            86: 
        !            87:        so_len = sizeof(len);
        !            88:        if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &so_len) != 0) {
        !            89:                errmsg = string_format("%s: %s",
        !            90:                        "getsockopt(SO_RCVBUF)", strerror(errno));
        !            91:                goto abort;
        !            92:        }
        !            93: 
        !            94:        putmsg(1, "opened for %s", ifname.c_str());
        !            95:        putmsg(1, "warning: communicating with the localhost is not possible");
        !            96: 
        !            97:        // AFPacket では ifup スクリプトは実行しない
        !            98: 
        !            99:        return true;
        !           100: 
        !           101:  abort:
        !           102:        putmsg(1, "%s", errmsg.c_str());
        !           103:        Close();
        !           104:        return false;
        !           105: }
        !           106: 
        !           107: // クローズ
        !           108: // (private)
        !           109: void
        !           110: NetDriverAFPacket::Close()
        !           111: {
        !           112:        if (IsOpen()) {
        !           113:                close(fd);
        !           114:                fd = -1;
        !           115:        }
        !           116: }
        !           117: 
        !           118: // モニタ (ドライバ依存情報のみ)
        !           119: void
        !           120: NetDriverAFPacket::MonitorUpdateMD(TextScreen& screen)
        !           121: {
        !           122:        screen.Print(0, 1, "Interface: %s", ifname.c_str());
        !           123: }
        !           124: 
        !           125: // パケットを送信する
        !           126: bool
        !           127: NetDriverAFPacket::SendPacket(const std::vector<uint8>& data)
        !           128: {
        !           129:        int n;
        !           130: 
        !           131:        assert(IsOpen());
        !           132: 
        !           133:        putlog(2, "SendPacket %zu bytes", data.size());
        !           134:        tx_pkts++;
        !           135:        tx_bytes += data.size();
        !           136: 
        !           137:        n = sendto(fd, data.data(), data.size(), 0,
        !           138:                (const sockaddr *)&sll, sizeof(sll));
        !           139:        if (n == -1) {
        !           140:                warn("NetDriverAFPacket.SendPacket: sendto failed: fd=%d datalen=%zu",
        !           141:                        fd, data.size());
        !           142:                return false;
        !           143:        }
        !           144: 
        !           145:        if (n < (int)data.size()) {
        !           146:                return false;
        !           147:        }
        !           148:        return true;
        !           149: }
        !           150: 
        !           151: // パケットを受信する
        !           152: ssize_t
        !           153: NetDriverAFPacket::RecvPacket()
        !           154: {
        !           155:        uint8 buf[10240];
        !           156:        ssize_t rv;
        !           157: 
        !           158:        rv = recv(fd, buf, sizeof(buf), 0);
        !           159:        if (rv > 0) {
        !           160:                RecvEnqueue(buf, rv);
        !           161:        }
        !           162:        return rv;
        !           163: }
        !           164: 
        !           165: // インタフェース番号を返す。
        !           166: // auto のときは選択したインタフェース名を ifname にセットする。
        !           167: // インタフェースが決定できないときは errmsg をセットして 0 を返す。
        !           168: int
        !           169: NetDriverAFPacket::SelectInterface()
        !           170: {
        !           171:        int ifindex = 0;
        !           172:        struct ifaddrs *ifa_list, *ifa;
        !           173: 
        !           174:        if (ifname == "auto") {
        !           175:                // インタフェースを探す
        !           176:                int level = 1;
        !           177: 
        !           178:                if (getifaddrs(&ifa_list) == -1) {
        !           179:                        errmsg = "getifaddrs";
        !           180:                        return 0;
        !           181:                }
        !           182: 
        !           183:                for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
        !           184:                        if ((ifa->ifa_flags & IFF_UP) == 0) {
        !           185:                                continue;
        !           186:                        }
        !           187:                        if (ifa->ifa_addr == NULL) {
        !           188:                                continue;
        !           189:                        }
        !           190:                        // AF_PACKET をサポートするインタフェースを探す
        !           191:                        if (ifa->ifa_addr->sa_family != AF_PACKET) {
        !           192:                                continue;
        !           193:                        }
        !           194: 
        !           195:                        // ETHERNET を探す
        !           196:                        sockaddr_ll *sa = (sockaddr_ll *)ifa->ifa_addr;
        !           197:                        if (sa->sll_hatype != ARPHRD_ETHER) {
        !           198:                                continue;
        !           199:                        }
        !           200: 
        !           201:                        if (ifindex == 0) {
        !           202:                                // 最初に見つかったものを採用
        !           203:                                ifname = ifa->ifa_name;
        !           204:                                ifindex = sa->sll_ifindex;
        !           205:                        } else {
        !           206:                                // インタフェース候補が 2個以上ある場合はログレベル 0 にしたい
        !           207:                                level = 0;
        !           208:                                break;
        !           209:                        }
        !           210:                }
        !           211:                freeifaddrs(ifa_list);
        !           212: 
        !           213:                if (ifindex == 0) {
        !           214:                        errmsg = "auto could not find a suitable interface";
        !           215:                        return ifindex;
        !           216:                }
        !           217: 
        !           218:                putmsg(level, "auto-selected ifname \"%s\"", ifname.c_str());
        !           219: 
        !           220:        } else {
        !           221:                ifindex = if_nametoindex(ifname.c_str());
        !           222:                if (ifindex == 0) {
        !           223:                        errmsg = string_format("interface %s not found", ifname.c_str());
        !           224:                }
        !           225:        }
        !           226:        return ifindex;
        !           227: }

unix.superglobalmegacorp.com

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